MUSE Pipeline Reference Manual  1.0.2
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 int
201 {
202  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, -1);
203  if (!aList->size) {
204  return 1;
205  }
206 
207  /* Check the images */
208  int nx = cpl_image_get_size_x(muse_imagelist_get(aList, 0)->data),
209  ny = cpl_image_get_size_y(muse_imagelist_get(aList, 0)->data);
210  unsigned int k;
211  for (k = 1; k < aList->size; k++) {
212  if (cpl_image_get_size_x(muse_imagelist_get(aList, k)->data) != nx ||
213  cpl_image_get_size_y(muse_imagelist_get(aList, k)->data) != ny) {
214  return k+1;
215  }
216  } /* for k (all images except first) */
217  return 0;
218 } /* muse_imagelist_is_uniform() */
219 
220 /*---------------------------------------------------------------------------*/
227 /*---------------------------------------------------------------------------*/
228 void
230 {
231  if (!aList) {
232  return;
233  }
234  double t0 = muse_pfits_get_exptime(muse_imagelist_get(aList, 0)->header);
235  cpl_msg_info(__func__, " index median mean stdev scale");
236  unsigned int k;
237  for (k = 0; k < aList->size; k++) {
238  muse_image *image = muse_imagelist_get(aList, k);
239  if (!image) {
240  const char *empty = "----------";
241  cpl_msg_info(__func__, "%5d %10s %10s %10s %10s" , k,
242  empty, empty, empty, empty);
243  continue;
244  }
245  double t = muse_pfits_get_exptime(image->header),
246  scale = t0 / t;
247  cpl_msg_info(__func__, "%5d %10.2f %10.2f %10.2f %10.2f", k,
248  cpl_image_get_median(image->data),
249  cpl_image_get_mean(image->data),
250  cpl_image_get_stdev(image->data), scale);
251  } /* for k (all images) */
252 } /* muse_imagelist_dump_statistics() */
253 
254 /*---------------------------------------------------------------------------*/
266 /*---------------------------------------------------------------------------*/
267 cpl_error_code
269 {
270  cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
271  double t0 = muse_pfits_get_exptime(muse_imagelist_get(aList, 0)->header);
272  cpl_msg_info(__func__, "Scale all images to %7.2fs exposure time",
273  t0);
274  cpl_msg_debug(__func__, "Image EXPTIME scale");
275  cpl_msg_debug(__func__, " 1 %7.2fs 1.000", t0);
276  unsigned int k;
277  for (k = 1; k < aList->size; k++) {
278  muse_image *image = muse_imagelist_get(aList, k);
279  double t = muse_pfits_get_exptime(image->header),
280  scale = t0 / t;
281  cpl_msg_debug(__func__, "%4d %7.2fs %6.3f", k+1, t, scale);
282  muse_image_scale(image, scale);
283  cpl_propertylist_update_double(image->header, "EXPTIME", t0);
284  } /* for k (images except first) */
285  return CPL_ERROR_NONE;
286 } /* muse_imagelist_scale_exptime() */
287 
288 /*---------------------------------------------------------------------------*/
322 /*---------------------------------------------------------------------------*/
323 cpl_bivector *
324 muse_imagelist_compute_ron(muse_imagelist *aList, int aHalfsize, int aNSamples)
325 {
326  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, NULL);
327  unsigned int nvalues = aList->size;
328  cpl_ensure(nvalues > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
329  nvalues -= 1; /* we'll get one value less than images */
330  unsigned char ifu = muse_utils_get_ifu(aList->list[0]->header); /* IFU for output */
331 
332  /* Use an image to store the read-out noise values and the errors for the *
333  * four quadrants of the CCD. Store RON in columns 1-4, RONERR in 5-8. */
334  cpl_image *ronimage = cpl_image_new(4 * 2, nvalues, CPL_TYPE_DOUBLE);
335 
336  /* loop through all images and compute difference image with the next one */
337  unsigned int k; /* image index */
338  unsigned char n; /* quadrant number */
339  for (k = 0; k < nvalues; k++) {
340  /* loop through the quadrants of all images */
341  cpl_image *diff = cpl_image_subtract_create(aList->list[k]->data,
342  aList->list[k+1]->data);
343  for (n = 1; n <= 4; n++) {
344  /* here we want gain in count/adu */
345  double gain = muse_pfits_get_gain(aList->list[k]->header, n);
346  cpl_size *window = muse_quadrants_get_window(aList->list[k], n);
347 #if 0
348  cpl_stats *s = cpl_stats_new_from_image_window(diff, CPL_STATS_ALL,
349  window[0], window[2],
350  window[1], window[3]);
351  cpl_msg_debug(__func__, "Quadrant %hhu stats: %f+/-%f %f %f..%f\n", n,
352  cpl_stats_get_mean(s), cpl_stats_get_stdev(s),
353  cpl_stats_get_median(s),
354  cpl_stats_get_min(s), cpl_stats_get_max(s));
355  cpl_stats_delete(s);
356 #endif
357  double ron = 100., ronerr = 1000.;
358  unsigned int niter = 0;
359  #pragma omp critical (cpl_flux_get_noise)
360  do {
361  srand(niter++ * 100 + 1); /* as if running without seed the first time */
362  cpl_flux_get_noise_window(diff, window, aHalfsize, aNSamples,
363  &ron, &ronerr);
364  } while (ronerr > 0.1 * ron && niter < 5);
365 #if 0
366  cpl_msg_debug(__func__, "--> intermediate RON=%f+/-%f (GAIN=%f)",
367  ron, ronerr, gain);
368 #endif
369  /* use the formula from Howell "CCD Astronomy" */
370  ron *= gain / sqrt(2);
371  ronerr *= gain / sqrt(2);
372  cpl_image_set(ronimage, n, k+1, ron);
373  cpl_image_set(ronimage, n+4, k+1, ronerr);
374  cpl_free(window);
375  } /* for n (quadrants) */
376  cpl_image_delete(diff);
377  } /* for k (all but one bias files) */
378 
379  /* compute and store the final values */
380  cpl_vector *ron = cpl_vector_new(4),
381  *ronerr = cpl_vector_new(4);
382  for (n = 1; n <= 4; n++) {
383 #if 0 /* for debugging generate and use some more values */
384  cpl_stats *ronstats, *ronerrstats;
385  ronstats = cpl_stats_new_from_image_window(ronimage, CPL_STATS_ALL,
386  n, 1, n, nvalues);
387  ronerrstats = cpl_stats_new_from_image_window(ronimage, CPL_STATS_ALL,
388  n+4, 1, n+4, nvalues);
389  cpl_msg_debug(__func__, "IFU %hhu, quadrant %hhu RON: %f+/-%f %f %f..%f\n",
390  ifu, n, cpl_stats_get_mean(ronstats),
391  cpl_stats_get_stdev(ronstats),
392  cpl_stats_get_median(ronstats),
393  cpl_stats_get_min(ronstats),
394  cpl_stats_get_max(ronstats));
395  cpl_msg_debug(__func__, "IFU %hhu, quadrant %hhu RONERR: %f+/-%f %f %f..%f\n",
396  ifu, n, cpl_stats_get_mean(ronerrstats),
397  cpl_stats_get_stdev(ronerrstats),
398  cpl_stats_get_median(ronerrstats),
399  cpl_stats_get_min(ronerrstats),
400  cpl_stats_get_max(ronerrstats));
401  cpl_stats_delete(ronstats);
402  cpl_stats_delete(ronerrstats);
403 #endif
404 
405  double ronmean = cpl_image_get_mean_window(ronimage, n, 1, n, nvalues),
406  ronmeanerr = cpl_image_get_mean_window(ronimage, n+4, 1, n+4, nvalues);
407  cpl_vector_set(ron, n - 1, ronmean);
408  cpl_vector_set(ronerr, n - 1, ronmeanerr);
409 
410  /* take RON value in first input header as reference */
411  double ronheader = muse_pfits_get_ron(aList->list[0]->header, n);
412  if (ronmean < 1. || ronmean > 5.) {
413  cpl_msg_warning(__func__, "The RON value computed for quadrant %hhu in "
414  "IFU %hhu is likely wrong (outside the range 1..5 count: "
415  "%.2f +/- %.2f count; the raw header says %.2f count)", n,
416  ifu, ronmean, ronmeanerr, ronheader);
417  } /* if bad RON */
418  } /* for n (quadrants) */
419  cpl_image_delete(ronimage);
420 
421  /* now apply the read-out noise by filling the variance accordingly */
422  nvalues = muse_imagelist_get_size(aList); /* now use all images */
423  for (k = 0; k < nvalues; k++) {
424  for (n = 1; n <= 4; n++) {
425  double gain = muse_pfits_get_gain(aList->list[k]->header, n);
426  /* read-out noise + error of the read-out noise is *
427  * (1 + 1/n_bias) * sigma_bias^2 *
428  * where n_bias is the number of pixels used to determine the *
429  * RON and sigma_bias is the RON itself (here still in adu) */
430  double variance = (1. + 1. / (pow(2 * aHalfsize + 1, 2) * aNSamples))
431  * pow(cpl_vector_get(ron, n-1)/gain, 2);
432  if (k == 0) { /* output message for the first image in the list */
433  cpl_msg_info(__func__, "IFU %hhu, quadrant %hhu: RON = %.3f +/- %.3f "
434  "count ==> variance = %.4f adu**2 (1st value of image "
435  "series)", ifu, n, cpl_vector_get(ron, n-1),
436  cpl_vector_get(ronerr, n-1), variance);
437  } /* if */
438  /* get the image window for this quadrant */
439  cpl_size *window = muse_quadrants_get_window(aList->list[k], n);
440  /* fill the variance into the stat extension of the input image */
441  cpl_image_fill_window(aList->list[k]->stat, window[0], window[2],
442  window[1], window[3], variance);
443  cpl_free(window);
444  } /* for n (quadrants) */
445  } /* for k (all images in list) */
446 
447  return cpl_bivector_wrap_vectors(ron, ronerr);
448 } /* muse_imagelist_compute_ron() */
449 
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:695
unsigned char muse_utils_get_ifu(const cpl_propertylist *aHeaders)
Find out the IFU/channel from which this header originated.
Definition: muse_utils.c:99
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:539
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:513
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:347
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.