MUSE Pipeline Reference Manual  2.1.1
muse_imagelist.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) 2005-2014 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 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 /*----------------------------------------------------------------------------*
27  * Includes *
28  *----------------------------------------------------------------------------*/
29 #include <stdio.h>
30 #include <float.h>
31 #include <math.h>
32 #include <string.h>
33 #include <cpl.h>
34 
35 #include "muse_imagelist.h"
36 
37 #include "muse_dfs.h"
38 #include "muse_pfits.h"
39 #include "muse_quadrants.h"
40 #include "muse_quality.h"
41 #include "muse_utils.h"
42 
43 /*---------------------------------------------------------------------------*/
49 /*---------------------------------------------------------------------------*/
50 
53 /*---------------------------------------------------------------------------*/
58 /*---------------------------------------------------------------------------*/
61 {
62  muse_imagelist *images = cpl_calloc(sizeof(muse_imagelist), 1);
63  /* the components are nulled automatically by using calloc */
64  return images;
65 } /* muse_imagelist_new() */
66 
67 /*---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------*/
77 void
79 {
80  if (!aList) {
81  return;
82  }
83  unsigned int k;
84  for (k = 0; k < aList->size; k++) {
85  muse_image_delete(aList->list[k]);
86  }
87  cpl_free(aList->list);
88  aList->list = NULL;
89  aList->size = 0;
90  cpl_free(aList);
91 } /* muse_imagelist_delete() */
92 
93 /*---------------------------------------------------------------------------*/
101 /*---------------------------------------------------------------------------*/
102 unsigned int
104 {
105  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, 0);
106  return aList->size;
107 } /* muse_imagelist_get_size() */
108 
109 /*---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------*/
125 muse_image *
126 muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
127 {
128  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, NULL);
129  cpl_ensure(aIdx < aList->size, CPL_ERROR_ACCESS_OUT_OF_RANGE, NULL);
130 
131  return aList->list[aIdx];
132 } /* muse_imagelist_get() */
133 
134 /*---------------------------------------------------------------------------*/
154 /*---------------------------------------------------------------------------*/
155 cpl_error_code
156 muse_imagelist_set(muse_imagelist *aList, muse_image *aImage, unsigned int aIdx)
157 {
158  cpl_ensure_code(aList && aImage, CPL_ERROR_NULL_INPUT);
159  /* check that this muse_image * is not already present! */
160  unsigned int k;
161  for (k = 0; k < aList->size; k++) {
162  /* just check that the address is not the same */
163  cpl_ensure_code(aList->list[k] != aImage, CPL_ERROR_ILLEGAL_INPUT);
164  } /* for k (all images) */
165 
166  if (aIdx >= aList->size || aList->list == NULL) {
167  aList->list = (muse_image **)cpl_realloc(aList->list,
168  sizeof(muse_image *) * (aIdx+1));
169  /* null out all entries from the old size to the new size */
170  for (k = aList->size; k <= aIdx; k++) {
171  aList->list[k] = NULL;
172  } /* for k (all new list positions) */
173  aList->size = aIdx + 1;
174  } /* if list needs to be expanded */
175  /* make sure this location in the list is empty */
176  muse_image_delete(aList->list[aIdx]);
177  aList->list[aIdx] = aImage;
178  return CPL_ERROR_NONE;
179 } /* muse_imagelist_set() */
180 
181 /*---------------------------------------------------------------------------*/
198 /*---------------------------------------------------------------------------*/
199 muse_image *
200 muse_imagelist_unset(muse_imagelist *aList, unsigned int aIdx)
201 {
202  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, NULL);
203  cpl_ensure(aIdx < aList->size, CPL_ERROR_ACCESS_OUT_OF_RANGE, NULL);
204 
205  /* keep the image pointer around to return it below */
206  muse_image *image = aList->list[aIdx];
207 
208  /* move the rest of the images one position backwards */
209  unsigned int k;
210  for (k = aIdx; k < aList->size - 1; k++) {
211  aList->list[k] = aList->list[k + 1];
212  }
213  /* NULL out the last pointer to be sure... */
214  aList->list[aList->size - 1] = NULL;
215  /* one image less */
216  aList->size--;
217 
218  return image;
219 } /* muse_imagelist_unset() */
220 
221 /*---------------------------------------------------------------------------*/
238 /*---------------------------------------------------------------------------*/
239 int
241 {
242  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, -1);
243  if (!aList->size) {
244  return 1;
245  }
246 
247  /* Check the images */
248  int nx = cpl_image_get_size_x(muse_imagelist_get(aList, 0)->data),
249  ny = cpl_image_get_size_y(muse_imagelist_get(aList, 0)->data);
250  unsigned int k;
251  for (k = 1; k < aList->size; k++) {
252  if (cpl_image_get_size_x(muse_imagelist_get(aList, k)->data) != nx ||
253  cpl_image_get_size_y(muse_imagelist_get(aList, k)->data) != ny) {
254  return k+1;
255  }
256  } /* for k (all images except first) */
257  return 0;
258 } /* muse_imagelist_is_uniform() */
259 
260 /*---------------------------------------------------------------------------*/
267 /*---------------------------------------------------------------------------*/
268 void
270 {
271  if (!aList) {
272  return;
273  }
274  double t0 = muse_pfits_get_exptime(muse_imagelist_get(aList, 0)->header);
275  cpl_msg_info(__func__, " index median mean stdev scale");
276  unsigned int k;
277  for (k = 0; k < aList->size; k++) {
278  muse_image *image = muse_imagelist_get(aList, k);
279  if (!image) {
280  const char *empty = "----------";
281  cpl_msg_info(__func__, "%5d %10s %10s %10s %10s" , k,
282  empty, empty, empty, empty);
283  continue;
284  }
285  double t = muse_pfits_get_exptime(image->header),
286  scale = t0 / t;
287  cpl_msg_info(__func__, "%5d %10.2f %10.2f %10.2f %10.2f", k,
288  cpl_image_get_median(image->data),
289  cpl_image_get_mean(image->data),
290  cpl_image_get_stdev(image->data), scale);
291  } /* for k (all images) */
292 } /* muse_imagelist_dump_statistics() */
293 
294 /*---------------------------------------------------------------------------*/
306 /*---------------------------------------------------------------------------*/
307 cpl_error_code
309 {
310  cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
311  double t0 = muse_pfits_get_exptime(muse_imagelist_get(aList, 0)->header);
312  cpl_msg_info(__func__, "Scale all images to %7.2fs exposure time",
313  t0);
314  cpl_msg_debug(__func__, "Image EXPTIME scale");
315  cpl_msg_debug(__func__, " 1 %7.2fs 1.000", t0);
316  unsigned int k;
317  for (k = 1; k < aList->size; k++) {
318  muse_image *image = muse_imagelist_get(aList, k);
319  double t = muse_pfits_get_exptime(image->header),
320  scale = t0 / t;
321  cpl_msg_debug(__func__, "%4d %7.2fs %6.3f", k+1, t, scale);
322  muse_image_scale(image, scale);
323  cpl_propertylist_update_double(image->header, "EXPTIME", t0);
324  } /* for k (images except first) */
325  return CPL_ERROR_NONE;
326 } /* muse_imagelist_scale_exptime() */
327 
328 /*---------------------------------------------------------------------------*/
362 /*---------------------------------------------------------------------------*/
363 cpl_bivector *
364 muse_imagelist_compute_ron(muse_imagelist *aList, int aHalfsize, int aNSamples)
365 {
366  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, NULL);
367  unsigned int nvalues = aList->size;
368  cpl_ensure(nvalues > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
369  nvalues -= 1; /* we'll get one value less than images */
370  unsigned char ifu = muse_utils_get_ifu(aList->list[0]->header); /* IFU for output */
371 
372  /* Use an image to store the read-out noise values and the errors for the *
373  * four quadrants of the CCD. Store RON in columns 1-4, RONERR in 5-8. */
374  cpl_image *ronimage = cpl_image_new(4 * 2, nvalues, CPL_TYPE_DOUBLE);
375 
376  /* loop through all images and compute difference image with the next one */
377  unsigned int k; /* image index */
378  unsigned char n; /* quadrant number */
379  for (k = 0; k < nvalues; k++) {
380  /* loop through the quadrants of all images */
381  cpl_image *diff = cpl_image_subtract_create(aList->list[k]->data,
382  aList->list[k+1]->data);
383  for (n = 1; n <= 4; n++) {
384  /* here we want gain in count/adu */
385  double gain = muse_pfits_get_gain(aList->list[k]->header, n);
386  cpl_size *window = muse_quadrants_get_window(aList->list[k], n);
387 #if 0
388  cpl_stats *s = cpl_stats_new_from_image_window(diff, CPL_STATS_ALL,
389  window[0], window[2],
390  window[1], window[3]);
391  cpl_msg_debug(__func__, "Quadrant %hhu stats: %f+/-%f %f %f..%f\n", n,
392  cpl_stats_get_mean(s), cpl_stats_get_stdev(s),
393  cpl_stats_get_median(s),
394  cpl_stats_get_min(s), cpl_stats_get_max(s));
395  cpl_stats_delete(s);
396 #endif
397  double ron = 100., ronerr = 1000.;
398  unsigned int niter = 0;
399  #pragma omp critical (cpl_flux_get_noise)
400  do {
401  srand(niter++ * 100 + 1); /* as if running without seed the first time */
402  cpl_flux_get_noise_window(diff, window, aHalfsize, aNSamples,
403  &ron, &ronerr);
404  } while (ronerr > 0.1 * ron && niter < 5);
405 #if 0
406  cpl_msg_debug(__func__, "--> intermediate RON=%f+/-%f (GAIN=%f)",
407  ron, ronerr, gain);
408 #endif
409  /* use the formula from Howell "CCD Astronomy" */
410  ron *= gain / sqrt(2);
411  ronerr *= gain / sqrt(2);
412  cpl_image_set(ronimage, n, k+1, ron);
413  cpl_image_set(ronimage, n+4, k+1, ronerr);
414  cpl_free(window);
415  } /* for n (quadrants) */
416  cpl_image_delete(diff);
417  } /* for k (all but one bias files) */
418 
419  /* compute and store the final values */
420  cpl_vector *ron = cpl_vector_new(4),
421  *ronerr = cpl_vector_new(4);
422  for (n = 1; n <= 4; n++) {
423 #if 0 /* for debugging generate and use some more values */
424  cpl_stats *ronstats, *ronerrstats;
425  ronstats = cpl_stats_new_from_image_window(ronimage, CPL_STATS_ALL,
426  n, 1, n, nvalues);
427  ronerrstats = cpl_stats_new_from_image_window(ronimage, CPL_STATS_ALL,
428  n+4, 1, n+4, nvalues);
429  cpl_msg_debug(__func__, "IFU %hhu, quadrant %hhu RON: %f+/-%f %f %f..%f\n",
430  ifu, n, cpl_stats_get_mean(ronstats),
431  cpl_stats_get_stdev(ronstats),
432  cpl_stats_get_median(ronstats),
433  cpl_stats_get_min(ronstats),
434  cpl_stats_get_max(ronstats));
435  cpl_msg_debug(__func__, "IFU %hhu, quadrant %hhu RONERR: %f+/-%f %f %f..%f\n",
436  ifu, n, cpl_stats_get_mean(ronerrstats),
437  cpl_stats_get_stdev(ronerrstats),
438  cpl_stats_get_median(ronerrstats),
439  cpl_stats_get_min(ronerrstats),
440  cpl_stats_get_max(ronerrstats));
441  cpl_stats_delete(ronstats);
442  cpl_stats_delete(ronerrstats);
443 #endif
444 
445  double ronmean = cpl_image_get_mean_window(ronimage, n, 1, n, nvalues),
446  ronmeanerr = cpl_image_get_mean_window(ronimage, n+4, 1, n+4, nvalues);
447  cpl_vector_set(ron, n - 1, ronmean);
448  cpl_vector_set(ronerr, n - 1, ronmeanerr);
449 
450  /* take RON value in first input header as reference */
451  double ronheader = muse_pfits_get_ron(aList->list[0]->header, n);
452  if (ronmean < 1. || ronmean > 5.) {
453  cpl_msg_warning(__func__, "The RON value computed for quadrant %hhu in "
454  "IFU %hhu is likely wrong (outside the range 1..5 count: "
455  "%.2f +/- %.2f count; the raw header says %.2f count)", n,
456  ifu, ronmean, ronmeanerr, ronheader);
457  } /* if bad RON */
458  } /* for n (quadrants) */
459  cpl_image_delete(ronimage);
460 
461  /* now apply the read-out noise by filling the variance accordingly */
462  nvalues = muse_imagelist_get_size(aList); /* now use all images */
463  for (k = 0; k < nvalues; k++) {
464  for (n = 1; n <= 4; n++) {
465  double gain = muse_pfits_get_gain(aList->list[k]->header, n);
466  /* read-out noise + error of the read-out noise is *
467  * (1 + 1/n_bias) * sigma_bias^2 *
468  * where n_bias is the number of pixels used to determine the *
469  * RON and sigma_bias is the RON itself (here still in adu) */
470  double variance = (1. + 1. / (pow(2 * aHalfsize + 1, 2) * aNSamples))
471  * pow(cpl_vector_get(ron, n-1)/gain, 2);
472  if (k == 0) { /* output message for the first image in the list */
473  cpl_msg_info(__func__, "IFU %hhu, quadrant %hhu: RON = %.3f +/- %.3f "
474  "count ==> variance = %.4f adu**2 (1st value of image "
475  "series)", ifu, n, cpl_vector_get(ron, n-1),
476  cpl_vector_get(ronerr, n-1), variance);
477  } /* if */
478  /* get the image window for this quadrant */
479  cpl_size *window = muse_quadrants_get_window(aList->list[k], n);
480  /* fill the variance into the stat extension of the input image */
481  cpl_image_fill_window(aList->list[k]->stat, window[0], window[2],
482  window[1], window[3], variance);
483  cpl_free(window);
484  } /* for n (quadrants) */
485  } /* for k (all images in list) */
486 
487  return cpl_bivector_wrap_vectors(ron, ronerr);
488 } /* muse_imagelist_compute_ron() */
489 
Structure definition for a collection of muse_images.
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
Definition: muse_image.c:85
cpl_size * muse_quadrants_get_window(const muse_image *aImage, unsigned char aQuadrant)
Determine the data window of a given quadrant on the CCD.
int muse_image_scale(muse_image *aImage, double aScale)
Scale a muse_image with correct treatment of variance.
Definition: muse_image.c:703
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
double muse_pfits_get_gain(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find the detector gain (in units of count/adu)
Definition: muse_pfits.c:686
cpl_image * data
the data extension
Definition: muse_image.h:46
cpl_image * stat
the statistics extension
Definition: muse_image.h:64
void muse_imagelist_delete(muse_imagelist *aList)
Free the memory of the MUSE image list.
void muse_imagelist_dump_statistics(muse_imagelist *aList)
Show statistics of a muse_image list.
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:40
cpl_propertylist * header
the FITS header
Definition: muse_image.h:72
unsigned int muse_imagelist_get_size(muse_imagelist *aList)
Return the number of stored images.
cpl_error_code muse_imagelist_scale_exptime(muse_imagelist *aList)
Scale muse_images to a common exposure time.
muse_image * muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
Get the muse_image of given list index.
double muse_pfits_get_ron(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find the detector read-out noise
Definition: muse_pfits.c:660
int muse_imagelist_is_uniform(muse_imagelist *aList)
Check that all images in the muse_imagelist have the same size.
cpl_bivector * muse_imagelist_compute_ron(muse_imagelist *aList, int aHalfsize, int aNSamples)
Compute the read-out noise from bias images in an imagelist.
muse_imagelist * muse_imagelist_new(void)
Create a new (empty) MUSE image list.
double muse_pfits_get_exptime(const cpl_propertylist *aHeaders)
find out the exposure time
Definition: muse_pfits.c:382
muse_image ** list
The list of muse_images.
unsigned int size
cpl_error_code muse_imagelist_set(muse_imagelist *aList, muse_image *aImage, unsigned int aIdx)
Set the muse_image of given list index.
muse_image * muse_imagelist_unset(muse_imagelist *aList, unsigned int aIdx)
Unset the muse_image at given list index from the list.