MUSE Pipeline Reference Manual  0.18.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  *
5  * This file is part of the MUSE Instrument Pipeline
6  * Copyright (C) 2005-2011 European Southern Observatory
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 /*----------------------------------------------------------------------------*
28  * Includes *
29  *----------------------------------------------------------------------------*/
30 #include <stdio.h>
31 #include <float.h>
32 #include <math.h>
33 #include <string.h>
34 #include <cpl.h>
35 
36 #include "muse_imagelist.h"
37 
38 #include "muse_dfs.h"
39 #include "muse_pfits.h"
40 #include "muse_quadrants.h"
41 #include "muse_quality.h"
42 #include "muse_utils.h"
43 
44 /*---------------------------------------------------------------------------*/
50 /*---------------------------------------------------------------------------*/
51 
54 /*---------------------------------------------------------------------------*/
59 /*---------------------------------------------------------------------------*/
62 {
63  muse_imagelist *images = cpl_calloc(sizeof(muse_imagelist), 1);
64  /* the components are nulled automatically by using calloc */
65  return images;
66 } /* muse_imagelist_new() */
67 
68 /*---------------------------------------------------------------------------*/
77 /*---------------------------------------------------------------------------*/
78 void
80 {
81  if (!aList) {
82  return;
83  }
84  unsigned int k;
85  for (k = 0; k < aList->size; k++) {
86  muse_image_delete(aList->list[k]);
87  }
88  cpl_free(aList->list);
89  aList->list = NULL;
90  aList->size = 0;
91  cpl_free(aList);
92 } /* muse_imagelist_delete() */
93 
94 /*---------------------------------------------------------------------------*/
102 /*---------------------------------------------------------------------------*/
103 unsigned int
105 {
106  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, 0);
107  return aList->size;
108 } /* muse_imagelist_get_size() */
109 
110 /*---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------*/
126 muse_image *
127 muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
128 {
129  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, NULL);
130  cpl_ensure(aIdx < aList->size, CPL_ERROR_ACCESS_OUT_OF_RANGE, NULL);
131 
132  return aList->list[aIdx];
133 } /* muse_imagelist_get() */
134 
135 /*---------------------------------------------------------------------------*/
155 /*---------------------------------------------------------------------------*/
156 cpl_error_code
157 muse_imagelist_set(muse_imagelist *aList, muse_image *aImage, unsigned int aIdx)
158 {
159  cpl_ensure_code(aList && aImage, CPL_ERROR_NULL_INPUT);
160  /* check that this muse_image * is not already present! */
161  unsigned int k;
162  for (k = 0; k < aList->size; k++) {
163  /* just check that the address is not the same */
164  cpl_ensure_code(aList->list[k] != aImage, CPL_ERROR_ILLEGAL_INPUT);
165  } /* for k (all images) */
166 
167  if (aIdx >= aList->size || aList->list == NULL) {
168  aList->list = (muse_image **)cpl_realloc(aList->list,
169  sizeof(muse_image *) * (aIdx+1));
170  /* null out all entries from the old size to the new size */
171  for (k = aList->size; k <= aIdx; k++) {
172  aList->list[k] = NULL;
173  } /* for k (all new list positions) */
174  aList->size = aIdx + 1;
175  } /* if list needs to be expanded */
176  /* make sure this location in the list is empty */
177  muse_image_delete(aList->list[aIdx]);
178  aList->list[aIdx] = aImage;
179  return CPL_ERROR_NONE;
180 } /* muse_imagelist_set() */
181 
182 /*---------------------------------------------------------------------------*/
199 /*---------------------------------------------------------------------------*/
200 int
202 {
203  cpl_ensure(aList, CPL_ERROR_NULL_INPUT, -1);
204  if (!aList->size) {
205  return 1;
206  }
207 
208  /* Check the images */
209  int nx = cpl_image_get_size_x(muse_imagelist_get(aList, 0)->data),
210  ny = cpl_image_get_size_y(muse_imagelist_get(aList, 0)->data);
211  unsigned int k;
212  for (k = 1; k < aList->size; k++) {
213  if (cpl_image_get_size_x(muse_imagelist_get(aList, k)->data) != nx ||
214  cpl_image_get_size_y(muse_imagelist_get(aList, k)->data) != ny) {
215  return k+1;
216  }
217  } /* for k (all images except first) */
218  return 0;
219 } /* muse_imagelist_is_uniform() */
220 
221 /*---------------------------------------------------------------------------*/
228 /*---------------------------------------------------------------------------*/
229 void
231 {
232  if (!aList) {
233  return;
234  }
235  double t0 = muse_pfits_get_exptime(muse_imagelist_get(aList, 0)->header);
236  cpl_msg_info(__func__, " index median mean stdev scale");
237  unsigned int k;
238  for (k = 0; k < aList->size; k++) {
239  muse_image *image = muse_imagelist_get(aList, k);
240  if (!image) {
241  const char *empty = "----------";
242  cpl_msg_info(__func__, "%5d %10s %10s %10s %10s" , k,
243  empty, empty, empty, empty);
244  continue;
245  }
246  double t = muse_pfits_get_exptime(image->header),
247  scale = t0 / t;
248  cpl_msg_info(__func__, "%5d %10.2f %10.2f %10.2f %10.2f", k,
249  cpl_image_get_median(image->data),
250  cpl_image_get_mean(image->data),
251  cpl_image_get_stdev(image->data), scale);
252  } /* for k (all images) */
253 } /* muse_imagelist_dump_statistics() */
254 
255 /*---------------------------------------------------------------------------*/
267 /*---------------------------------------------------------------------------*/
268 cpl_error_code
270 {
271  cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
272  double t0 = muse_pfits_get_exptime(muse_imagelist_get(aList, 0)->header);
273  cpl_msg_info(__func__, "Scale all images to %7.2fs exposure time",
274  t0);
275  cpl_msg_debug(__func__, "Image EXPTIME scale");
276  cpl_msg_debug(__func__, " 1 %7.2fs 1.000", t0);
277  unsigned int k;
278  for (k = 1; k < aList->size; k++) {
279  muse_image *image = muse_imagelist_get(aList, k);
280  double t = muse_pfits_get_exptime(image->header),
281  scale = t0 / t;
282  cpl_msg_debug(__func__, "%4d %7.2fs %6.3f", k+1, t, scale);
283  muse_image_scale(image, scale);
284  cpl_propertylist_update_double(image->header, "EXPTIME", t0);
285  } /* for k (images except first) */
286  return CPL_ERROR_NONE;
287 } /* muse_imagelist_scale_exptime() */
288 
289 /*---------------------------------------------------------------------------*/
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 
328  unsigned int nvalues = aList->size - 1; /* we'll get one value less than images */
329  /* Use an image to store the read-out noise values and the errors for the *
330  * four quadrants of the CCD. Store RON in columns 1-4, RONERR in 5-8. */
331  cpl_image *ronimage = cpl_image_new(4 * 2, nvalues, CPL_TYPE_DOUBLE);
332 
333  /* loop through all images and compute difference image with the next one */
334  unsigned int k; /* image index */
335  unsigned char n; /* quadrant number */
336  for (k = 0; k < nvalues; k++) {
337  /* loop through the quadrants of all images */
338  cpl_image *diff = cpl_image_subtract_create(aList->list[k]->data,
339  aList->list[k+1]->data);
340  for (n = 1; n <= 4; n++) {
341  /* here we want gain in count/adu */
342  double gain = muse_pfits_get_gain(aList->list[k]->header, n);
343  cpl_size *window = muse_quadrants_get_window(aList->list[k], n);
344 #if 0
345  cpl_stats *s = cpl_stats_new_from_image_window(diff, CPL_STATS_ALL,
346  window[0], window[2],
347  window[1], window[3]);
348  cpl_msg_debug(__func__, "Quadrant %hhu stats: %f+/-%f %f %f..%f\n", n,
349  cpl_stats_get_mean(s), cpl_stats_get_stdev(s),
350  cpl_stats_get_median(s),
351  cpl_stats_get_min(s), cpl_stats_get_max(s));
352  cpl_stats_delete(s);
353 #endif
354  double ron = 100., ronerr = 1000.;
355  unsigned int niter = 0;
356  #pragma omp critical (cpl_flux_get_noise)
357  do {
358  srand(niter++ * 100 + 1); /* as if running without seed the first time */
359  cpl_flux_get_noise_window(diff, window, aHalfsize, aNSamples,
360  &ron, &ronerr);
361  } while (ronerr > 0.1 * ron && niter < 5);
362 #if 0
363  cpl_msg_debug(__func__, "--> intermediate RON=%f+/-%f (GAIN=%f)",
364  ron, ronerr, gain);
365 #endif
366  /* use the formula from Howell "CCD Astronomy" */
367  ron *= gain / sqrt(2);
368  ronerr *= gain / sqrt(2);
369  cpl_image_set(ronimage, n, k+1, ron);
370  cpl_image_set(ronimage, n+4, k+1, ronerr);
371  cpl_free(window);
372  } /* for n (quadrants) */
373  cpl_image_delete(diff);
374  } /* for k (all but one bias files) */
375 
376  /* compute and store the final values */
377  cpl_vector *ron = cpl_vector_new(4),
378  *ronerr = cpl_vector_new(4);
379  for (n = 1; n <= 4; n++) {
380 #if 0 // for debugging generate and use some more values
381  cpl_stats *ronstats, *ronerrstats;
382  ronstats = cpl_stats_new_from_image_window(ronimage, CPL_STATS_ALL,
383  n, 1, n, nvalues);
384  ronerrstats = cpl_stats_new_from_image_window(ronimage, CPL_STATS_ALL,
385  n+4, 1, n+4, nvalues);
386  cpl_msg_debug(__func__, "Quadrant %hhu RON: %f+/-%f %f %f..%f\n", n,
387  cpl_stats_get_mean(ronstats),
388  cpl_stats_get_stdev(ronstats),
389  cpl_stats_get_median(ronstats),
390  cpl_stats_get_min(ronstats),
391  cpl_stats_get_max(ronstats));
392  cpl_msg_debug(__func__, "Quadrant %hhu RONERR: %f+/-%f %f %f..%f\n", n,
393  cpl_stats_get_mean(ronerrstats),
394  cpl_stats_get_stdev(ronerrstats),
395  cpl_stats_get_median(ronerrstats),
396  cpl_stats_get_min(ronerrstats),
397  cpl_stats_get_max(ronerrstats));
398  cpl_stats_delete(ronstats);
399  cpl_stats_delete(ronerrstats);
400 #endif
401 
402  double ronmean = cpl_image_get_mean_window(ronimage, n, 1, n, nvalues),
403  ronmeanerr = cpl_image_get_mean_window(ronimage, n+4, 1, n+4, nvalues);
404  cpl_vector_set(ron, n - 1, ronmean);
405  cpl_vector_set(ronerr, n - 1, ronmeanerr);
406 
407  /* take RON value in first input header as reference */
408  double ronheader = muse_pfits_get_ron(aList->list[0]->header, n),
409  ron2sl = ronmean - 2 * ronmeanerr, /* 2 sigma lower than RON */
410  ron2sh = ronmean + 2 * ronmeanerr; /* 2 sigma higher than RON */
411  if (ronheader < ron2sl || ronheader > ron2sh) {
412  cpl_msg_warning(__func__, "The RON value for quadrant %hhu in the input "
413  "FITS header (RON=%f) is likely wrong as it is outside "
414  "a 2 sigma range (%f < %f < %f) around the computed "
415  "value", n, ronheader, ron2sl, ronmean, ron2sh);
416  }
417  } /* for n (quadrants) */
418  cpl_image_delete(ronimage);
419 
420  /* now apply the read-out noise by filling the variance accordingly */
421  nvalues = muse_imagelist_get_size(aList); /* now use all images */
422  for (k = 0; k < nvalues; k++) {
423  for (n = 1; n <= 4; n++) {
424  double gain = muse_pfits_get_gain(aList->list[k]->header, n);
425  /* read-out noise + error of the read-out noise is *
426  * (1 + 1/n_bias) * sigma_bias^2 *
427  * where n_bias is the number of pixels used to determine the *
428  * RON and sigma_bias is the RON itself (here still in adu) */
429  double variance = (1. + 1. / (pow(2 * aHalfsize + 1, 2) * aNSamples))
430  * pow(cpl_vector_get(ron, n-1)/gain, 2);
431  if (k == 0) { /* output message for the first image in the list */
432  cpl_msg_info(__func__, "Quadrant %hhu: RON=%f, RONERR=%f, Variance=%f",
433  n, cpl_vector_get(ron, n-1), cpl_vector_get(ronerr, n-1),
434  variance);
435  } /* if */
436  /* get the image window for this quadrant */
437  cpl_size *window = muse_quadrants_get_window(aList->list[k], n);
438  /* fill the variance into the stat extension of the input image */
439  cpl_image_fill_window(aList->list[k]->stat, window[0], window[2],
440  window[1], window[3], variance);
441  cpl_free(window);
442  } /* for n (quadrants) */
443  } /* for k (all images in list) */
444 
445  return cpl_bivector_wrap_vectors(ron, ronerr);
446 } /* muse_imagelist_compute_ron() */
447 
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:84
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:687
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:470
cpl_image * data
the data extension
Definition: muse_image.h:47
cpl_image * stat
the statistics extension
Definition: muse_image.h:65
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:41
cpl_propertylist * header
the FITS header
Definition: muse_image.h:73
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:444
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:278
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.