VISIR Pipeline Reference Manual  4.1.0
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 = 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  cpl_propertylist_set_double(plist, "CRPIX1",
649  cpl_propertylist_get_double(plist, "CRPIX1") - cutlx);
650  cpl_propertylist_set_double(plist, "CRPIX2",
651  cpl_propertylist_get_double(plist, "CRPIX2") - cutly);
652 
653  cpl_image * nimg = cpl_image_extract(*img, cutlx, cutly, cutux, cutuy);
654  cpl_image * nwgt = cpl_image_extract(*wgt, cutlx, cutly, cutux, cutuy);
655  cpl_image * nctr = cpl_image_extract(*ctr, cutlx, cutly, cutux, cutuy);
656  cpl_image_delete(*img);
657  cpl_image_delete(*wgt);
658  cpl_image_delete(*ctr);
659  *img = nimg;
660  *wgt = nwgt;
661  *ctr = nctr;
662 
663  return cpl_error_get_code();
664 }
665 
666 
667 static cpl_error_code
668 check_inputs(const cpl_frameset * framelist, const char * config)
669 {
670  irplib_framelist * alldata = irplib_framelist_cast(framelist);
671  irplib_framelist * data = irplib_framelist_extract(alldata,
672  VISIR_UTIL_CORRECTED);
673  irplib_framelist * errors = irplib_framelist_extract(alldata, "ERROR_MAP");
674  irplib_framelist_load_propertylist_all(data, 0, "ESO QC", CPL_FALSE);
675  error_if(irplib_framelist_get_size(data) !=
676  irplib_framelist_get_size(errors), CPL_ERROR_ILLEGAL_INPUT,
677  "Unequal number of data and error frames");
678  skip_if(irplib_framelist_contains(data, "ESO QC BEAMID", CPL_TYPE_STRING,
679  CPL_FALSE, 0.0));
680 
681  error_if(access(config, R_OK) != 0, CPL_ERROR_FILE_NOT_FOUND,
682  "Swarp configuration not found: %s", config);
683  end_skip;
684 
685  irplib_framelist_delete(alldata);
687  irplib_framelist_delete(errors);
688  return cpl_error_get_code();
689 }
690 
691 
692 /*----------------------------------------------------------------------------*/
699 /*----------------------------------------------------------------------------*/
700 static int visir_util_run_swarp(cpl_frameset * framelist,
701  const cpl_parameterlist * parlist)
702 {
703  cpl_frameset * usedframes = cpl_frameset_new();
704  cpl_propertylist * plist = NULL;
705  cx_list * imglist = cx_list_new();
706  cx_list * errlist = cx_list_new();
707 
708  skip_if(check_swarp());
709 
710  const cpl_boolean output_all =
711  irplib_parameterlist_get_bool(parlist, PACKAGE,
712  RECIPE_STRING, "output-all");
713  const char * config =
714  irplib_parameterlist_get_string(parlist, PACKAGE,
715  RECIPE_STRING, "config_fname");
716  const char * extra =
717  irplib_parameterlist_get_string(parlist, PACKAGE,
718  RECIPE_STRING, "extra_config");
719  const int nmax_procs =
720  irplib_parameterlist_get_int(parlist, PACKAGE,
721  RECIPE_STRING, "nprocs");
722  if (visir_str_par_is_empty(extra))
723  extra = "";
724 
725  error_if(visir_str_par_is_empty(config), CPL_ERROR_FILE_NOT_FOUND,
726  "A swarp configuration file is required. "
727  "You can create a default configuration with: swarp -d");
728 
729  skip_if(check_inputs(framelist, config));
730 
731  unlink(SWARP_DATA_FILES);
732  unlink(SWARP_COADD_HEAD);
733 
734  skip_if(0);
735 
736  create_swarp_frames(imglist, errlist, framelist);
737  error_if(cx_list_size(imglist) == 0 || cx_list_size(errlist) == 0,
738  CPL_ERROR_ILLEGAL_INPUT, "No frames tagged "
739  VISIR_UTIL_CORRECTED" and "VISIR_UTIL_ERROR_MAP" found");
740 
741  skip_if(generate_coaddition_header(imglist, config, extra));
742 
743  {
744  const cpl_size nfiles = cx_list_size(imglist);
745  pid_t pids[nfiles];
746  unsigned long beamids[nfiles];
747  float imgwgts[nfiles];
748  unsigned long nmax_beamid = 0;
749  cpl_image * av[nfiles];
750  cpl_image * wav[nfiles];
751  cpl_image * cimg = NULL;
752  cpl_image * cwgt = NULL;
753  cpl_image * cctr = NULL;
754 
755  for (cpl_size j = 0; j < nfiles; j++)
756  av[j] = wav[j] = NULL;
757 
758  skip_if(coadd_images(pids, beamids, imgwgts, usedframes,
759  imglist, errlist, nmax_procs, parlist));
760 
761  for (cpl_size i = 0; i < nfiles; i++)
762  nmax_beamid = CX_MAX(nmax_beamid, beamids[i] + 1);
763 
764  error_if((cpl_size)nmax_beamid - 1 > nfiles,
765  CPL_ERROR_UNSUPPORTED_MODE,
766  "Only consecutive BEAMID's supported");
767 
768  if (output_all && nfiles > 1)
769  save_single_images(framelist, nfiles, pids, usedframes, parlist);
770 
771  skip_if(0);
772 
773  plist = generate_beam_averages(av, wav, imgwgts, nfiles, pids, beamids);
774  skip_if(plist == NULL);
775 
776  generate_combined_image(av, wav, imgwgts, nmax_beamid, &cimg, &cwgt,
777  &cctr, VISIR_AVG_COMB);
778  for (cpl_size i = 0; i < nfiles; i++) {
779  cpl_image_delete(av[i]);
780  cpl_image_delete(wav[i]);
781  }
782 
783  cut_bad_edges(&cimg, &cwgt, &cctr, plist);
784 
785  irplib_dfs_save_image(framelist, parlist, usedframes, cimg,
786  CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
787  "COADDED_IMAGE_COMBINED", plist, NULL,
788  visir_pipe_id, "swarp_coadd_img_all.fits");
789  irplib_dfs_save_image(framelist, parlist, usedframes, cwgt,
790  CPL_BPP_IEEE_FLOAT, RECIPE_STRING,
791  "COADDED_WEIGHT_COMBINED", plist, NULL,
792  visir_pipe_id, "swarp_coadd_wgt_all.fits");
793  irplib_dfs_save_image(framelist, parlist, usedframes, cctr,
794  CPL_TYPE_INT, RECIPE_STRING,
795  "COADDED_CONTRIBUTION_COMBINED", plist, NULL,
796  visir_pipe_id, "swarp_coadd_ctr_all.fits");
797  cpl_image_delete(cimg);
798  cpl_image_delete(cwgt);
799  cpl_image_delete(cctr);
800  skip_if(0);
801  }
802 
803  end_skip;
804 
805  unlink(SWARP_DATA_FILES);
806  unlink(SWARP_COADD_HEAD);
807  cx_list_destroy(imglist, (cx_free_func)cpl_frame_delete);
808  cx_list_destroy(errlist, (cx_free_func)cpl_frame_delete);
809  cpl_frameset_delete(usedframes);
810  cpl_propertylist_delete(plist);
811  return cpl_error_get_code();
812 }
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:827
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.