MUSE Pipeline Reference Manual  2.1.1
muse_product_split.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2015 European Southern Observatory
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #include <string.h>
23 #include <muse.h>
24 
25 /*----------------------------------------------------------------------------*/
54 /*----------------------------------------------------------------------------*/
55 
58 #define PRINT_USAGE(rc) \
59  fprintf(stderr, "Usage: %s [ -s ] [ -d ] FILENAME\n", argv[0]); \
60  cpl_end(); return (rc);
61 
62 int main(int argc, char **argv)
63 {
64  cpl_init(CPL_INIT_DEFAULT);
66 
67  if (argc <= 1) {
68  /* filename is needed */
69  PRINT_USAGE(1);
70  }
71 
72  /* argument processing */
73  cpl_boolean dodelete = CPL_FALSE, /* do not delete input by default */
74  dosign = CPL_FALSE; /* do not sign by default */
75  char *iname = NULL; /* filename */
76  int i;
77  for (i = 1; i < argc; i++) {
78  if (strncmp(argv[i], "-s", 3) == 0) {
79  dosign = CPL_TRUE;
80  } else if (strncmp(argv[i], "-d", 3) == 0) {
81  dodelete = CPL_TRUE;
82  } else if (strncmp(argv[i], "-", 1) == 0) { /* unallowed options */
83  PRINT_USAGE(9);
84  } else {
85  if (iname) {
86  break; /* we have the required name, skip the rest */
87  }
88  if (!iname) {
89  iname = argv[i]; /* set the filename */
90  }
91  }
92  } /* for i (all arguments) */
93 
94  cpl_errorstate state = cpl_errorstate_get();
95 
96  /* for a file to split, there need to be at least two extensions */
97  int next = cpl_fits_count_extensions(iname);
98  if (next < 2) {
99  PRINT_USAGE(10);
100  }
101  cpl_propertylist *header = cpl_propertylist_load(iname, 0);
102  const char *tag = muse_pfits_get_pro_catg(header);
103  printf("Splitting \"%s\" (PRO.CATG %s, %d extensions).\n", iname, tag, next);
104 
105  /* loop through all extensions, and create a frameset with all split files */
106  cpl_frameset *fset = cpl_frameset_new();
107  /* first assume what we are not dealing with a merged *
108  * 3-extension MUSE image (that's a bit more complicated) */
109  int iext;
110  for (iext = 1; iext <= next; iext++) {
111  /* read extension header */
112  cpl_propertylist *hext = cpl_propertylist_load(iname, iext);
113  /* see what type of object we have */
114  unsigned char ifu = muse_utils_get_ifu(hext);
115  const char *xtension = cpl_propertylist_get_string(hext, "XTENSION"),
116  *extname = muse_pfits_get_extname(hext);
117  if (!xtension) {
118  fprintf(stderr, "Broken FITS extension (missing XTENSION, extension "
119  "%d)\n", iext);
120  cpl_propertylist_delete(hext);
121  continue;
122  }
123 
124  enum {
125  IS_BINTABLE,
126  IS_IMAGE,
127  IS_CHANNEL_CUBE,
128  IS_MUSE_IMAGE_DATA,
129  IS_MUSE_IMAGE_DQ,
130  IS_MUSE_IMAGE_STAT,
131  IS_OTHER
132  } exttype = IS_OTHER;
133  if (!strncmp(xtension, "BINTABLE", 8)) {
134  exttype = IS_BINTABLE;
135  } else if (!strncmp(xtension, "IMAGE", 8)) {
136  char *chan = cpl_sprintf("CHAN%02hhu", ifu),
137  *chandata = cpl_sprintf("CHAN%02hhu.DATA", ifu),
138  *chandq = cpl_sprintf("CHAN%02hhu.DQ", ifu),
139  *chanstat = cpl_sprintf("CHAN%02hhu.STAT", ifu);
140  if (extname && !strncmp(extname, chan, strlen(chan) + 1)) {
141  exttype = IS_IMAGE;
142  } else if (extname && !strncmp(extname, chandata, strlen(chandata) + 1)) {
143  exttype = IS_MUSE_IMAGE_DATA;
144  } else if (extname && !strncmp(extname, chandq, strlen(chandq) + 1)) {
145  exttype = IS_MUSE_IMAGE_DQ;
146  } else if (extname && !strncmp(extname, chanstat, strlen(chanstat) + 1)) {
147  exttype = IS_MUSE_IMAGE_STAT;
148  } else if (extname && /* here only compare to the number, not what's... */
149  !strncmp(extname, chan, strlen(chan)) && /* after it! */
150  muse_pfits_get_naxis(hext, 0) == 3) {
151  exttype = IS_CHANNEL_CUBE;
152  } else {
153  exttype = IS_OTHER;
154  }
155  cpl_free(chan);
156  cpl_free(chandata);
157  cpl_free(chandq);
158  cpl_free(chanstat);
159  } /* image extension */
160 
161  /* create output filename, prefixing the extension with the IFU number */
162  char *basefn = cpl_strdup(iname),
163  *end = strstr(basefn, ".fits");
164  if (end) {
165  *end = '\0'; /* strip off ".fits" */
166  }
167  char *outfn = cpl_sprintf("%s-%02hhu.fits", basefn, ifu);
168  cpl_free(basefn);
169 
170  /* now do the work to save the object */
171  switch (exttype) {
172  case IS_BINTABLE: {
173  printf("\tbinary table (XTENSION=\'%s\', EXTNAME=\'%s\')\n", xtension,
174  extname);
175  /* for tables, just merge primary and extension header and load and save the table */
176  cpl_table *table = cpl_table_load(iname, iext, 1);
177  cpl_propertylist *hout = cpl_propertylist_duplicate(header);
178  cpl_propertylist_append(hout, hext);
179  if (strlen(extname) == 6) {
180  /* the original extensions don't have any header, not even EXTNAME */
181  cpl_table_save(table, hout, NULL, outfn, CPL_IO_CREATE);
182  } else {
183  cpl_propertylist *hextout = cpl_propertylist_new();
184  /* find the part after the dot and use that for the output EXTNAME */
185  char *extnew = strchr(extname, '.');
186  if (extnew) {
187  extnew += 1; /* go after the dot */
188  cpl_propertylist_append_string(hextout, "EXTNAME", extnew);
189  }
190  cpl_table_save(table, hout, hextout, outfn, CPL_IO_CREATE);
191  cpl_propertylist_delete(hextout);
192  }
193  cpl_table_delete(table);
194  cpl_propertylist_delete(hout);
195  break;
196  }
197  case IS_IMAGE: {
198  printf("\tstandard image(XTENSION=\'%s\', EXTNAME=\'%s\')\n", xtension,
199  extname);
200  /* for normal images, just merge primary and extension header and load and save the image */
201  cpl_image *image = cpl_image_load(iname, CPL_TYPE_UNSPECIFIED, 0, iext);
202  cpl_propertylist *hout = cpl_propertylist_duplicate(header);
203  cpl_propertylist_append(hout, hext);
204  cpl_image_save(image, outfn, CPL_TYPE_UNSPECIFIED, hout, CPL_IO_CREATE);
205  cpl_image_delete(image);
206  cpl_propertylist_delete(hout);
207  break;
208  }
209  case IS_CHANNEL_CUBE: { /* handle the case of a cube (LSF_PROFILE!) */
210  printf("\tchannel cube (XTENSION=\'%s\', EXTNAME=\'%s\')\n", xtension,
211  extname);
212  /* for normal images, just merge primary and extension header and load and save the image */
213  cpl_imagelist *list = cpl_imagelist_load(iname, CPL_TYPE_UNSPECIFIED, iext);
214  cpl_propertylist *hout = cpl_propertylist_duplicate(header);
215  /* leave part after channel number in the extension header */
216  unsigned char dummy;
217  char extnamerest[KEYWORD_LENGTH];
218  sscanf(extname, "CHAN%02hhu.%s", &dummy, extnamerest);
219 #if 0
220  printf("%s -> %02hhu and %s\n", extname, dummy, extnamerest);
221 #endif
222  cpl_propertylist_update_string(hext, "EXTNAME", extnamerest);
223  /* add channel number to primary header */
224  char *chan = cpl_sprintf("CHAN%02hhu", ifu);
225  cpl_propertylist_update_string(hout, "EXTNAME", chan);
226  cpl_free(chan);
227  cpl_propertylist_copy_property_regexp(hout, hext, "^ESO ", 0);
228  cpl_propertylist_save(hout, outfn, CPL_IO_CREATE);
229  cpl_propertylist_erase_regexp(hext, "^ESO ", 0);
230  cpl_imagelist_save(list, outfn, CPL_TYPE_UNSPECIFIED, hext, CPL_IO_EXTEND);
231  cpl_imagelist_delete(list);
232  cpl_propertylist_delete(hout);
233  break;
234  }
235  case IS_MUSE_IMAGE_DATA: {
236  printf("\tMUSE image (XTENSION=\'%s\', EXTNAME=\'%s\')\n", xtension,
237  extname);
238  /* load all three extensions and them save them again */
239  muse_image *image = muse_image_load_from_extensions(iname, ifu);
240  muse_image_save(image, outfn);
241  muse_image_delete(image);
242  break;
243  }
244  case IS_MUSE_IMAGE_DQ:
245  case IS_MUSE_IMAGE_STAT:
246 #if 0
247  printf("MUSE OTHER (%s %s)\n", xtension, extname);
248 #endif
249  cpl_propertylist_delete(hext);
250  cpl_free(outfn);
251  continue; /* silently skip this extension */
252  default:
253  fprintf(stderr, "\tUnsupported FITS extension (XTENSION=\'%s\', "
254  "extension %d)\n", xtension, iext);
255  cpl_propertylist_delete(hext);
256  cpl_free(outfn);
257  continue;
258  }
259  cpl_propertylist_delete(hext);
260 
261  /* now we can add the written file to the (output) frameset */
262  cpl_frame *frame = cpl_frame_new();
263  cpl_frame_set_filename(frame, outfn);
264  cpl_free(outfn);
265  cpl_frame_set_tag(frame, tag);
266  cpl_frame_set_group(frame, CPL_FRAME_GROUP_PRODUCT);
267  /* should be of no consequence to set these to "none" */
268  cpl_frame_set_type(frame, CPL_FRAME_TYPE_NONE);
269  cpl_frame_set_level(frame, CPL_FRAME_LEVEL_NONE);
270 #if 0
271  printf("frame:\t");
272  cpl_frame_dump(frame, stdout);
273  fflush(stdout);
274 #endif
275  cpl_frameset_insert(fset, frame);
276  } /* for iext (all FITS extensions) */
277  cpl_propertylist_delete(header);
278 
279  int nout = cpl_frameset_get_size(fset);
280  if (dosign) {
281  printf("Signing %d output product%s...\n", nout, nout == 0 ? "" : "s");
282  cpl_dfs_sign_products(fset, CPL_DFS_SIGNATURE_DATAMD5 | CPL_DFS_SIGNATURE_CHECKSUM);
283  }
284  if (dodelete) {
285  printf("Deleting input file \"%s\"...\n", iname);
286  remove(iname);
287  }
288 
289  printf("Split output product%s:\n", nout == 0 ? "" : "s");
290  for (i = 0; i < nout; i++) {
291  const cpl_frame *frame = cpl_frameset_get_position_const(fset, i);
292  const char *fn = cpl_frame_get_filename(frame);
293  next = cpl_fits_count_extensions(fn);
294  printf("\t\"%s\" (%d FITS extensions)\n", fn, next);
295  } /* for i (all output frames) */
296  cpl_frameset_delete(fset);
297 
298  int rc = 0;
299  if (!cpl_errorstate_is_equal(state)) {
300  cpl_errorstate_dump(state, CPL_FALSE, muse_cplerrorstate_dump_some);
301  rc = 50;
302  }
303  cpl_memory_dump(); /* only active when CPL_MEMORY_MODE != 0 */
304  cpl_end();
305  return rc;
306 }
307 
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
Definition: muse_image.c:85
const char * muse_pfits_get_extname(const cpl_propertylist *aHeaders)
find out the extension name
Definition: muse_pfits.c:205
unsigned char muse_utils_get_ifu(const cpl_propertylist *aHeaders)
Find out the IFU/channel from which this header originated.
Definition: muse_utils.c:98
cpl_size muse_pfits_get_naxis(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the size of a given axis
Definition: muse_pfits.c:242
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:40
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
cpl_error_code muse_image_save(muse_image *aImage, const char *aFilename)
Save the three image extensions and the FITS headers of a MUSE image to a file.
Definition: muse_image.c:405
const char * muse_pfits_get_pro_catg(const cpl_propertylist *aHeaders)
find out the PRO category
Definition: muse_pfits.c:159
muse_image * muse_image_load_from_extensions(const char *aFilename, unsigned char aIFU)
Load the three extensions and the FITS headers of a MUSE image from extensions of a merged file...
Definition: muse_image.c:262
void muse_processing_recipeinfo(cpl_plugin *)
Output main pipeline configuration, inputs, and parameters.