VISIR Pipeline Reference Manual  4.1.7
visir_util_run_swarp.c
1 /*
2  * This file is part of the VISIR Pipeline
3  * Copyright (C) 2012,2013,2014 European Southern Observatory
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 /*-----------------------------------------------------------------------------
25  Includes
26  -----------------------------------------------------------------------------*/
27 
28 #include "visir_recipe.h"
29 #include "visir_utils.h"
30 #include "irplib_framelist.h"
31 #include <cxlist.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 /* for access */
38 #include <unistd.h>
39 
40 /*-----------------------------------------------------------------------------
41  Defines
42  -----------------------------------------------------------------------------*/
43 
44 #define RECIPE_STRING "visir_util_run_swarp"
45 #define DEFAULT_CONFIG VISIR_CONFIG_PATH "/visir_default.swarp"
46 #define SWARP_COADD_HEAD RECIPE_STRING "_coadd.head"
47 #define SWARP_DATA_FILES RECIPE_STRING "_data_files"
48 
49 /*-----------------------------------------------------------------------------
50  Private Functions prototypes
51  -----------------------------------------------------------------------------*/
52 
53 #ifdef VISIR_CHAIN
54 #define cpl_plugin_get_info visir_util_run_swarp_get_info
55 #endif
56 cpl_recipe_define(visir_util_run_swarp, VISIR_BINARY_VERSION,
57  "Julian Taylor", PACKAGE_BUGREPORT, "2012",
58  "Run swarp program to coadd images.",
59  "WARNING: this recipe is intented to be run in a "
60  "temporary directory, it does not clean up behind itself\n"
61  "The files listed in the Set Of Frames (sof-file) "
62  "must be tagged:\n"
63  "VISIR-chopnod-corrected-file.fits "VISIR_UTIL_CORRECTED"\n"
64  "VISIR-error-map.fits "VISIR_UTIL_ERROR_MAP
65  "\nIt will produce the coaddition of each input frame "
66  "separately and of all frames together.\n"
67  "The single frame product(s) will have a FITS card\n"
68  "'HIERARCH ESO PRO CATG' with a value of: COADDED_IMAGE and "
69  "COADDED_WEIGHT\nThe total coaddition will have the tags "
70  "COADDED_IMAGE_COMBINED and COADDED_WEIGHT_COMBINED");
71 
72 /*----------------------------------------------------------------------------*/
76 /*----------------------------------------------------------------------------*/
77 
78 /*-----------------------------------------------------------------------------
79  Functions code
80  -----------------------------------------------------------------------------*/
81 
82 typedef enum {
83  VISIR_AVG_COMB,
84  VISIR_SUM_COMB
85 } visir_comb_type;
86 
87 
88 /*----------------------------------------------------------------------------*/
96 /*----------------------------------------------------------------------------*/
97 static cpl_error_code
98 visir_util_run_swarp_fill_parameterlist(cpl_parameterlist * self)
99 {
100  const char * context = PACKAGE ".visir_util_run_swarp";
101 
102  skip_if(irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
103  "output-all", CPL_FALSE, NULL,
104  context, "Output a coadded image "
105  "for each input file in addition "
106  "to the complete coaddition."));
107 
108  skip_if(irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
109  "extra_config", "NONE", NULL, context,
110  "Additional configuration parameters"));
111 
112  skip_if(irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
113  "config_fname", DEFAULT_CONFIG, NULL,
114  context, "Swarp configure file name."));
115 
116  skip_if(irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
117  "nprocs", -1, NULL, context,
118  "Maximum number of swarp processes "
119  "that can be spawned simultaneously."));
120  end_skip;
121 
122  return cpl_error_get_code();
123 }
124 
125 
126 static cpl_error_code
127 check_swarp(void)
128 {
129  int ret = system(VISIR_SWARP_BIN " -v > /dev/null 2>/dev/null");
130  if (WEXITSTATUS(ret) != 0) {
131  cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
132  "swarp not found in PATH");
133  return CPL_ERROR_UNSUPPORTED_MODE;
134  }
135  return CPL_ERROR_NONE;
136 }
137 
138 
139 static cx_list *
140 sort_framelist(const cpl_frameset * allframes, const char * tag)
141 {
142  cx_list * frames = cx_list_new();
143 
144  FOR_EACH_FRAMESET_C(frm, allframes) {
145  if (tag == NULL || strcmp(cpl_frame_get_tag(frm), tag) == 0)
146  cx_list_push_back(frames, frm);
147  }
148 
149  cx_list_sort(frames, (cx_compare_func)visir_cmp_frm_fn);
150 
151  return frames;
152 }
153 
154 
155 static cpl_error_code
156 create_swarp_frames(cx_list * img_list, cx_list * err_list,
157  const cpl_frameset * frameset)
158 {
159  cx_list * imgframes = sort_framelist(frameset, VISIR_UTIL_CORRECTED);
160  cx_list * errframes = sort_framelist(frameset, VISIR_UTIL_ERROR_MAP);
161  skip_if(0);
162 
163  FOR_EACH_T(cpl_frame * frm, imgframes) {
164  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
165  cx_list_push_back(img_list, cpl_frame_duplicate(frm));
166  }
167 
168  FOR_EACH_T(cpl_frame * frm, errframes) {
169  cpl_frame_set_group(frm, CPL_FRAME_GROUP_RAW);
170  cx_list_push_back(err_list, cpl_frame_duplicate(frm));
171  }
172 
173  /* FIXME: check #ext of frames */
174  error_if(cx_list_size(err_list) != 0 &&
175  cx_list_size(img_list) != cx_list_size(err_list),
176  CPL_ERROR_UNSUPPORTED_MODE,
177  "Number of error frames does not match image frames");
178 
179  end_skip;
180 
181  cx_list_delete(imgframes);
182  cx_list_delete(errframes);
183 
184  return cpl_error_get_code();
185 }
186 
187 
188 /*----------------------------------------------------------------------------*/
203 /*----------------------------------------------------------------------------*/
204 static pid_t
205 run_swarp(cpl_frame * imgfrm, cpl_frame * errfrm,
206  const cpl_parameterlist * parlist)
207 {
208  pid_t pid = fork();
209  if (pid == 0) {
210  char datafile[128];
211  char errorfile[128];
212  char coadd_img[128];
213  char coadd_weight[128];
214  const char * config =
215  irplib_parameterlist_get_string(parlist, PACKAGE,
216  RECIPE_STRING, "config_fname");
217  const char * extra =
218  irplib_parameterlist_get_string(parlist, PACKAGE,
219  RECIPE_STRING, "extra_config");
220  if (strcasecmp(extra, "NONE") == 0)
221  extra = "";
222  pid_t cpid = getpid();
223  sprintf(datafile, "swarp_data_%d.list", (int)cpid);
224  sprintf(errorfile, "swarp_error_%d.list", (int)cpid);
225  sprintf(coadd_img, "tmp_coadd_%d.fits", (int)cpid);
226  sprintf(coadd_weight, "tmp_coadd_wgt_%d.fits", (int)cpid);
227 
228  FILE * data = fopen(datafile, "w");
229  fprintf(data, "%s\n", cpl_frame_get_filename(imgfrm));
230  fclose(data);
231 
232  FILE * error = fopen(errorfile, "w");
233  fprintf(error, "%s\n", cpl_frame_get_filename(errfrm));
234  fclose(error);
235 
236  /* duplicate the header defining the final projection
237  * to each output file */
238  char * cmd = cpl_sprintf("cp "SWARP_COADD_HEAD" tmp_coadd_%d.head",
239  (int)cpid);
240  int status = system(cmd);
241  cpl_free(cmd);
242  if (WEXITSTATUS(status) != 0) {
243  cpl_msg_info(cpl_func, "copy of coaddition header failed");
244  _exit(WEXITSTATUS(status));
245  }
246 
247  cmd = cpl_sprintf(VISIR_SWARP_BIN " -c %s @%s -NTHREADS 1 "
248  "-BLANK_BADPIXELS Y "
249  "-WEIGHT_IMAGE @%s "
250  "-WEIGHT_TYPE MAP_RMS %s "
251  "-IMAGEOUT_NAME %s "
252  "-WEIGHTOUT_NAME %s "
253  "> /dev/null 2>/dev/null",
254  config, datafile, errorfile, extra,
255  coadd_img, coadd_weight);
256  cpl_msg_debug(cpl_func, "%s", cmd);
257  status = system(cmd);
258  cpl_free(cmd);
259  cmd = cpl_sprintf("tmp_coadd_%d.head", (int)cpid);
260  unlink(cmd);
261 
262  cpl_free(cmd);
263  _exit(WEXITSTATUS(status));
264  }
265  else {
266  return pid;
267  }
268 }
269 
270 
271 static cpl_error_code
272 generate_coaddition_header(const cx_list * imglist, const char * config, const char * extra)
273 {
274  /* generate coaddition header which is read by each coaddition
275  * process to get the correct final output projection */
276  FILE * data = fopen(SWARP_DATA_FILES, "w");
277  char * cmd = cpl_sprintf(VISIR_SWARP_BIN " -c %s @"SWARP_DATA_FILES
278  " -IMAGEOUT_NAME "SWARP_COADD_HEAD
279  " -HEADER_ONLY Y %s > /dev/null 2>/dev/null",
280  config, extra);
281  int status;
282 
283  FOR_EACH_T(cpl_frame * frm, imglist) {
284  int ret;
285  cpl_propertylist * plist =
286  cpl_propertylist_load(cpl_frame_get_filename(frm), 0);
287  int cd11ok = plist && cpl_propertylist_has(plist, "CD1_1") &&
288  cpl_propertylist_get_double(plist, "CD1_1") != 0.;
289  int cd22ok = plist && cpl_propertylist_has(plist, "CD2_2") &&
290  cpl_propertylist_get_double(plist, "CD2_2") != 0.;
291  cpl_propertylist_delete(plist);
292  error_if (!cd11ok, CPL_ERROR_ILLEGAL_INPUT,
293  "CD1_1 WCS key missing or zero");
294  error_if (!cd22ok, CPL_ERROR_ILLEGAL_INPUT,
295  "CD2_2 WCS key missing or zero");
296 
297  cpl_msg_info(cpl_func, "%s", cpl_frame_get_filename(frm));
298  ret = fprintf(data, "%s\n", cpl_frame_get_filename(frm));
299  error_if(ret < 0, CPL_ERROR_FILE_IO, "Failed writting swarp file list");
300  }
301  fclose(data);
302 
303  cpl_msg_info(cpl_func, "Generating coaddition header");
304  cpl_msg_debug(cpl_func, "%s", cmd);
305  status = system(cmd);
306 
307  error_if(WEXITSTATUS(status) != 0, CPL_ERROR_FILE_IO, "Swarp failed");
308 
309  end_skip;
310  cpl_free(cmd);
311 
312  return cpl_error_get_code();
313 }
314 
315 
316 static cpl_error_code
317 coadd_images(pid_t * pids, unsigned long * beamids, float * imgwgts,
318  cpl_frameset * usedframes,
319  const cx_list * imglist, const cx_list * errlist,
320  const int nmax_procs, const cpl_parameterlist * parlist)
321 {
322  const int nfiles = cx_list_size(imglist);
323  int nprocs = CX_MIN(nfiles, visir_get_num_threads(CPL_FALSE));
324  int i = 0, done = 0;
325 
326  if (nmax_procs > 0)
327  nprocs = CX_MIN(nmax_procs, nprocs);
328 
329  for(cx_list_iterator iit = cx_list_begin(imglist),
330  eit = cx_list_begin(errlist);
331  iit != cx_list_end(imglist);
332  iit = cx_list_next(imglist, iit),
333  eit = cx_list_next(errlist, eit)) {
334  const char * beamid;
335  cpl_frame * ifrm = cx_list_get(imglist, iit);
336  cpl_frame * efrm = cx_list_get(errlist, eit);
337  cpl_propertylist * plist =
338  cpl_propertylist_load(cpl_frame_get_filename(ifrm), 0);
339  skip_if(0);
340 
341  beamid = cpl_propertylist_get_string(plist, "ESO QC BEAMID");
342  beamids[i] = strtoul(beamid, NULL, 10);
343  imgwgts[i] = visir_pfits_get_img_weight(plist);
344  cpl_propertylist_delete(plist);
345 
346  skip_if(0);
347 
348  cpl_frameset_insert(usedframes, cpl_frame_duplicate(ifrm));
349  cpl_frameset_insert(usedframes, cpl_frame_duplicate(efrm));
350  pids[i++] = run_swarp(ifrm, efrm, parlist);
351  cpl_msg_info(cpl_func, "Coadding file (%d/%d)", i, nfiles);
352  if (i - done >= nprocs) {
353  int status;
354  pid_t r = waitpid(-1, &status, 0);
355  error_if(r == -1 || !WIFEXITED(status) || WEXITSTATUS(status),
356  CPL_ERROR_FILE_IO, "Coaddition failed: %d %s",
357  WEXITSTATUS(status), r == -1 ? strerror(errno) : "");
358  done++;
359  }
360  }
361  for (int j = done; j < i; j++) {
362  int status;
363  pid_t r = waitpid(-1, &status, 0);
364  error_if(r == -1 || !WIFEXITED(status) || WEXITSTATUS(status),
365  CPL_ERROR_FILE_IO, "Coaddition failed: %d, %s",
366  WEXITSTATUS(status), r == -1 ? strerror(errno) : "");
367  }
368 
369  end_skip;
370 
371  return cpl_error_get_code();
372 }
373 
374 
375 static cpl_error_code
376 save_single_images(cpl_frameset * framelist, const cpl_size nfiles,
377  const pid_t * pids, const cpl_frameset * usedframes,
378  const cpl_parameterlist * parlist)
379 {
380  cpl_image * img = NULL;
381  cpl_image * wgt = NULL;
382  cpl_propertylist * plist = NULL;
383 
384  for (cpl_size j = 0; j < nfiles; j++) {
385  char coadd_img[200];
386  char coadd_wgt[200];
387 
388  sprintf(coadd_img, "tmp_coadd_%d.fits", (int)pids[j]);
389  sprintf(coadd_wgt, "tmp_coadd_wgt_%d.fits", (int)pids[j]);
390 
391  cpl_image_delete(img);
392  cpl_image_delete(wgt);
393  img = cpl_image_load(coadd_img, CPL_TYPE_UNSPECIFIED, 0, 0);
394  wgt = cpl_image_load(coadd_wgt, CPL_TYPE_UNSPECIFIED, 0, 0);
395  skip_if(0);
396 
397  cpl_propertylist_delete(plist);
398  plist = cpl_propertylist_load(coadd_img, 0);
399  skip_if(0);
400 
401  sprintf(coadd_img, "swarp_coadd_img_%03d.fits", (int)j);
402  sprintf(coadd_wgt, "swarp_coadd_wgt_%03d.fits", (int)j);
403 
404  skip_if(irplib_dfs_save_image(framelist, parlist, usedframes,
405  img, CPL_BPP_IEEE_FLOAT,
406  RECIPE_STRING, "COADDED_IMAGE",
407  plist, NULL, visir_pipe_id,
408  coadd_img));
409  skip_if(irplib_dfs_save_image(framelist, parlist, usedframes,
410  wgt, CPL_BPP_IEEE_FLOAT,
411  RECIPE_STRING, "COADDED_WEIGHT",
412  plist, NULL, visir_pipe_id,
413  coadd_wgt));
414  }
415 
416  end_skip;
417  cpl_image_delete(img);
418  cpl_image_delete(wgt);
419  cpl_propertylist_delete(plist);
420 
421  return cpl_error_get_code();
422 }
423 
424 
425 static cpl_propertylist *
426 generate_beam_averages(cpl_image ** av, cpl_image ** wav, float * imgwgts,
427  const cpl_size nfiles,
428  const pid_t * pids, const unsigned long * beamids)
429 {
430  /* all files are in the same projection so simply add them together */
431  cpl_image * img = NULL;
432  cpl_image * wgt = NULL;
433  cpl_propertylist * plist = NULL;
434  unsigned long max_beamid = 0;
435  float tmpwgts[nfiles];
436 
437  cpl_ensure(nfiles > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
438 
439  for (cpl_size j = 0; j < nfiles; j++) {
440  const unsigned long idx = beamids[j];
441  char coadd_img[200];
442  char coadd_wgt[200];
443 
444  cpl_image_delete(img);
445  cpl_image_delete(wgt);
446  sprintf(coadd_img, "tmp_coadd_%d.fits", (int)pids[j]);
447  sprintf(coadd_wgt, "tmp_coadd_wgt_%d.fits", (int)pids[j]);
448  img = cpl_image_load(coadd_img, CPL_TYPE_UNSPECIFIED, 0, 0);
449  wgt = cpl_image_load(coadd_wgt, CPL_TYPE_UNSPECIFIED, 0, 0);
450 
451  skip_if(0);
452 
453  if (plist == NULL)
454  plist = cpl_propertylist_load(coadd_img, 0);
455 
456  /* PIXEL mode is significantly faster and accurate enough for the
457  * fov of VISIR, set it back to TAN for other tools,
458  * note that swarp will flip the image and CD1_1 will have a different
459  * sign to account for that */
460  if (strcmp(cpl_propertylist_get_string(plist, "CTYPE1"),
461  "PIXEL") == 0) {
462  cpl_propertylist_set_string(plist, "CTYPE1", "RA---TAN");
463  cpl_propertylist_set_string(plist, "CTYPE2", "DEC--TAN");
464  cpl_propertylist_set_string(plist, "CUNIT1", "deg");
465  cpl_propertylist_set_string(plist, "CUNIT2", "deg");
466  }
467 
468  skip_if(0);
469 
470  cpl_image_multiply(img, wgt);
471  if (av[idx] == NULL) {
472  av[idx] = cpl_image_duplicate(img);
473  wav[idx] = cpl_image_duplicate(wgt);
474  }
475  else {
476  skip_if(cpl_image_add(av[idx], img));
477  skip_if(cpl_image_add(wav[idx], wgt));
478  }
479  max_beamid = CX_MAX(max_beamid, idx);
480  /* weights always the same for a single beam */
481  tmpwgts[idx] = imgwgts[j];
482  }
483 
484  for (unsigned long i = 0; i < max_beamid + 1; i++) {
485  cpl_image_divide(av[i], wav[i]);
486  imgwgts[i] = tmpwgts[i];
487  }
488 
489  end_skip;
490 
491  cpl_image_delete(img);
492  cpl_image_delete(wgt);
493 
494  return plist;
495 }
496 
497 
498 /*----------------------------------------------------------------------------*/
512 /*----------------------------------------------------------------------------*/
513 static cpl_error_code
514 generate_combined_image(cpl_image ** avg, cpl_image ** wgt,
515  const float * imgwgts, const unsigned long n,
516  cpl_image ** oimg, cpl_image ** owgt,
517  cpl_image ** octr, visir_comb_type ctype)
518 {
519  /* summing combine mode will lead to ugly images in case of bad pixels */
520  cpl_image * cimg = cpl_image_new(cpl_image_get_size_x(avg[0]),
521  cpl_image_get_size_y(avg[0]),
522  CPL_TYPE_FLOAT);
523  cpl_image * cwgt = cpl_image_new(cpl_image_get_size_x(wgt[0]),
524  cpl_image_get_size_y(wgt[0]),
525  CPL_TYPE_FLOAT);
526  cpl_image * contrib = cpl_image_new(cpl_image_get_size_x(wgt[0]),
527  cpl_image_get_size_y(wgt[0]),
528  CPL_TYPE_INT);
529  int wgtsum = 0;
530 
531  skip_if(0);
532  /* e_sum = sqrt(sum(sig^2)) / n :sig = sqrt(1/w)
533  w_sum = 1 / ((sum(1/w) / n ^ 2)) */
534  for (unsigned long i = 0; i < n; i++) {
535  cpl_mask * m = cpl_mask_threshold_image_create(wgt[i], -1, FLT_EPSILON);
536  cpl_image * bad = cpl_image_new_from_mask(m);
537  cpl_image_reject_from_mask(avg[i], m);
538  /* the beams have a non zero background which averages out over
539  * all beams, but in the case of bad pixels some values are missing
540  * which leads to artefacts if we don't correct the background */
541  cpl_image_subtract_scalar(avg[i], cpl_image_get_median(avg[i]));
542  cpl_image_fill_rejected(avg[i], 0);
543  cpl_mask_delete(m);
544 
545  /* will leave zero weight bad pixels at zero */
546  cpl_image_power(wgt[i], -1);
547  cpl_image_accept_all(wgt[i]);
548 
549  cpl_image_multiply_scalar(bad, imgwgts[i]);
550  cpl_image_subtract(contrib, bad);
551  cpl_image_delete(bad);
552 
553  skip_if(0);
554 
555  cpl_image_add(cimg, avg[i]);
556  cpl_image_add(cwgt, wgt[i]);
557 
558  wgtsum += imgwgts[i];
559  }
560 
561  cpl_image_add_scalar(contrib, wgtsum);
562  if (ctype == VISIR_AVG_COMB) {
563  cpl_image_divide(cimg, contrib);
564 
565  cpl_image_divide(cwgt, contrib);
566  cpl_image_divide(cwgt, contrib);
567  }
568  cpl_image_power(cwgt, -1);
569 
570  *oimg = cimg;
571  *owgt = cwgt;
572  *octr = contrib;
573 
574  end_skip;
575 
576  return cpl_error_get_code();
577 }
578 
579 
580 /* ---------------------------------------------------------------------------*/
592 /* ---------------------------------------------------------------------------*/
593 static cpl_error_code
594 cut_bad_edges(cpl_image ** img, cpl_image ** wgt, cpl_image ** ctr,
595  cpl_propertylist * plist)
596 {
597  const cpl_size nx = cpl_image_get_size_x(*ctr);
598  const cpl_size ny = cpl_image_get_size_y(*ctr);
599  const cpl_size max_contrib = cpl_image_get_max(*ctr);
600  const double ctr_cutoff = max_contrib == 2 ? 0.4 : 0.7;
601  cpl_size cutly = 0;
602  cpl_size cutuy = 0;
603  cpl_size cutlx = 0;
604  cpl_size cutux = 0;
605  for (cpl_size i = 0; i < ny / 2; i++) {
606  cpl_vector * row = cpl_vector_new_from_image_row(*ctr, i + 1);
607  double sum = cpl_vector_get_sum(row);
608  cpl_vector_delete(row);
609  if (sum >= max_contrib * nx * ctr_cutoff) {
610  break;
611  }
612  cutly = i + 1;
613  }
614  for (cpl_size i = ny - 1; i >= ny / 2; i--) {
615  cpl_vector * row = cpl_vector_new_from_image_row(*ctr, i + 1);
616  double sum = cpl_vector_get_sum(row);
617  cpl_vector_delete(row);
618  if (sum >= max_contrib * nx * ctr_cutoff) {
619  break;
620  }
621  cutuy = i + 1;
622  }
623  for (cpl_size i = 0; i < nx / 2; i++) {
624  cpl_vector * col = cpl_vector_new_from_image_column(*ctr, i + 1);
625  double sum = cpl_vector_get_sum(col);
626  cpl_vector_delete(col);
627  if (sum >= max_contrib * ny * ctr_cutoff) {
628  break;
629  }
630  cutlx = i + 1;
631  }
632  for (cpl_size i = nx - 1; i >= nx / 2; i--) {
633  cpl_vector * col = cpl_vector_new_from_image_column(*ctr, i + 1);
634  double sum = cpl_vector_get_sum(col);
635  cpl_vector_delete(col);
636  if (sum >= max_contrib * ny * ctr_cutoff) {
637  break;
638  }
639  cutux = i + 1;
640  }
641  cutlx += 1;
642  cutly += 1;
643  cutux -= 1;
644  cutuy -= 1;
645  cpl_msg_info(cpl_func, "Cutting low contribution edges "
646  "llx: %lld, lly: %lld, urx: %lld, ury: %lld",
647  cutlx, cutly, cutux, cutuy);
648 
649  /* make sure to only cut if something remains */
650  cpl_image * nimg, * nwgt, * nctr;
651  if (cutlx < cutux && cutly < cutuy) {
652  cpl_propertylist_set_double(plist, "CRPIX1",
653  cpl_propertylist_get_double(plist, "CRPIX1") - cutlx);
654  cpl_propertylist_set_double(plist, "CRPIX2",
655  cpl_propertylist_get_double(plist, "CRPIX2") - cutly);
656  nimg = cpl_image_extract(*img, cutlx, cutly, cutux, cutuy);
657  nwgt = cpl_image_extract(*wgt, cutlx, cutly, cutux, cutuy);
658  nctr = cpl_image_extract(*ctr, cutlx, cutly, cutux, cutuy);
659  }
660  else {
661  nimg = cpl_image_duplicate(*img);
662  nwgt = cpl_image_duplicate(*wgt);
663  nctr = cpl_image_duplicate(*ctr);
664  }
665  cpl_image_delete(*img);
666  cpl_image_delete(*wgt);
667  cpl_image_delete(*ctr);
668  *img = nimg;
669  *wgt = nwgt;
670  *ctr = nctr;
671 
672  return cpl_error_get_code();
673 }
674 
675 
676 static cpl_error_code
677 check_inputs(const cpl_frameset * framelist, const char * config)
678 {
679  irplib_framelist * alldata = irplib_framelist_cast(framelist);
680  irplib_framelist * data = irplib_framelist_extract(alldata,
681  VISIR_UTIL_CORRECTED);
682  irplib_framelist * errors = irplib_framelist_extract(alldata, "ERROR_MAP");
683  irplib_framelist_load_propertylist_all(data, 0, "ESO QC", CPL_FALSE);
684  error_if(irplib_framelist_get_size(data) !=
685  irplib_framelist_get_size(errors), CPL_ERROR_ILLEGAL_INPUT,
686  "Unequal number of data and error frames");
687  skip_if(irplib_framelist_contains(data, "ESO QC BEAMID", CPL_TYPE_STRING,
688  CPL_FALSE, 0.0));
689 
690  error_if(access(config, R_OK) != 0, CPL_ERROR_FILE_NOT_FOUND,
691  "Swarp configuration not found: %s", config);
692  end_skip;
693 
694  irplib_framelist_delete(alldata);
696  irplib_framelist_delete(errors);
697  return cpl_error_get_code();
698 }
699 
700 
701 /*----------------------------------------------------------------------------*/
708 /*----------------------------------------------------------------------------*/
709 static int visir_util_run_swarp(cpl_frameset * framelist,
710  const cpl_parameterlist * parlist)
711 {
712  cpl_frameset * usedframes = cpl_frameset_new();
713  cpl_propertylist * plist = NULL;
714  cx_list * imglist = cx_list_new();
715  cx_list * errlist = cx_list_new();
716 
717  skip_if(check_swarp());
718 
719  const cpl_boolean output_all =
720  irplib_parameterlist_get_bool(parlist, PACKAGE,
721  RECIPE_STRING, "output-all");
722  const char * config =
723  irplib_parameterlist_get_string(parlist, PACKAGE,
724  RECIPE_STRING, "config_fname");
725  const char * extra =
726  irplib_parameterlist_get_string(parlist, PACKAGE,
727  RECIPE_STRING, "extra_config");
728  const int nmax_procs =
729  irplib_parameterlist_get_int(parlist, PACKAGE,
730  RECIPE_STRING, "nprocs");
731  if (visir_str_par_is_empty(extra))
732  extra = "";
733 
734  error_if(visir_str_par_is_empty(config), CPL_ERROR_FILE_NOT_FOUND,
735  "A swarp configuration file is required. "
736  "You can create a default configuration with: swarp -d");
737 
738  skip_if(check_inputs(framelist, config));
739 
740  unlink(SWARP_DATA_FILES);
741  unlink(SWARP_COADD_HEAD);
742 
743  skip_if(0);
744 
745  create_swarp_frames(imglist, errlist, framelist);
746  error_if(cx_list_size(imglist) == 0 || cx_list_size(errlist) == 0,
747  CPL_ERROR_ILLEGAL_INPUT, "No frames tagged "
748  VISIR_UTIL_CORRECTED" and "VISIR_UTIL_ERROR_MAP" found");
749 
750  skip_if(generate_coaddition_header(imglist, config, extra));
751 
752  {
753  const cpl_size nfiles = cx_list_size(imglist);
754  pid_t pids[nfiles];
755  unsigned long beamids[nfiles];
756  float imgwgts[nfiles];
757  unsigned long nmax_beamid = 0;
758  cpl_image * av[nfiles];
759  cpl_image * wav[nfiles];
760  cpl_image * cimg = NULL;
761  cpl_image * cwgt = NULL;
762  cpl_image * cctr = NULL;
763 
764  for (cpl_size j = 0; j < nfiles; j++)
765  av[j] = wav[j] = NULL;
766 
767  skip_if(coadd_images(pids, beamids, imgwgts, usedframes,
768  imglist, errlist, nmax_procs, parlist));
769 
770  for (cpl_size i = 0; i < nfiles; i++)
771  nmax_beamid = CX_MAX(nmax_beamid, beamids[i] + 1);
772 
773  error_if((cpl_size)nmax_beamid - 1 > nfiles,
774  CPL_ERROR_UNSUPPORTED_MODE,
775  "Only consecutive BEAMID's supported");
776 
777  if (output_all && nfiles > 1)
778  save_single_images(framelist, nfiles, pids, usedframes, parlist);
779 
780  skip_if(0);
781 
782  plist = generate_beam_averages(av, wav, imgwgts, nfiles, pids, beamids);
783  skip_if(plist == NULL);
784 
785  generate_combined_image(av, wav, imgwgts, nmax_beamid, &cimg, &cwgt,
786  &cctr, VISIR_AVG_COMB);
787  for (cpl_size i = 0; i < nfiles; i++) {
788  cpl_image_delete(av[i]);
789  cpl_image_delete(wav[i]);
790  }
791 
792  cut_bad_edges(&cimg, &cwgt, &cctr, plist);
793 
794  irplib_dfs_save_image(framelist, parlist, usedframes, cimg,
795  CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
796  "COADDED_IMAGE_COMBINED", plist, NULL,
797  visir_pipe_id, "swarp_coadd_img_all.fits");
798  irplib_dfs_save_image(framelist, parlist, usedframes, cwgt,
799  CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
800  "COADDED_WEIGHT_COMBINED", plist, NULL,
801  visir_pipe_id, "swarp_coadd_wgt_all.fits");
802  irplib_dfs_save_image(framelist, parlist, usedframes, cctr,
803  CPL_TYPE_INT, RECIPE_STRING,
804  "COADDED_CONTRIBUTION_COMBINED", plist, NULL,
805  visir_pipe_id, "swarp_coadd_ctr_all.fits");
806  cpl_image_delete(cimg);
807  cpl_image_delete(cwgt);
808  cpl_image_delete(cctr);
809  skip_if(0);
810  }
811 
812  end_skip;
813 
814  unlink(SWARP_DATA_FILES);
815  unlink(SWARP_COADD_HEAD);
816  cx_list_destroy(imglist, (cx_free_func)cpl_frame_delete);
817  cx_list_destroy(errlist, (cx_free_func)cpl_frame_delete);
818  cpl_frameset_delete(usedframes);
819  cpl_propertylist_delete(plist);
820  return cpl_error_get_code();
821 }
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.
double visir_pfits_get_img_weight(const cpl_propertylist *self)
The relative weight of the image compared to the other images.
Definition: visir_pfits.c:877
irplib_framelist * irplib_framelist_extract(const irplib_framelist *self, const char *tag)
Extract the frames with the given tag from a 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.
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.