DETMON Pipeline Reference Manual  1.3.0
irplib_mkmaster.c
1 /* $Id: irplib_mkmaster.c,v 1.6 2013-02-27 16:00:51 jtaylor Exp $
2  *
3  * This file is part of the irplib package
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jtaylor $
23  * $Date: 2013-02-27 16:00:51 $
24  * $Revision: 1.6 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <math.h>
37 #include <string.h>
38 #include "irplib_mkmaster.h"
39 
40 /*----------------------------------------------------------------------------*/
44 /*----------------------------------------------------------------------------*/
45 
47 /*---------------------------------------------------------------------------*/
54 /*---------------------------------------------------------------------------*/
55 
56 /*-------------------------------------------------------------------------*/
68 /*--------------------------------------------------------------------------*/
69 static cpl_vector *
70 irplib_imagelist_get_clean_mean_levels(const cpl_imagelist* iml,
71  const double kappa,
72  const int nclip,
73  const double tolerance)
74 {
75 
76  int size=0;
77  int i=0;
78  cpl_vector* levels=NULL;
79  double* pval=NULL;
80  double mean=0;
81  double stdev=0;
82 
83 
84  cpl_error_ensure(iml != NULL, CPL_ERROR_NULL_INPUT, return(levels),
85  "Null input image list");
86  cpl_error_ensure(kappa >= 0, CPL_ERROR_ILLEGAL_INPUT, return(levels),
87  "Must be kappa>0");
88 
89  size=cpl_imagelist_get_size(iml);
90  levels=cpl_vector_new(size);
91  pval=cpl_vector_get_data(levels);
92 
93  for(i=0;i<size;i++) {
94  const cpl_image* img=cpl_imagelist_get_const(iml,i);
95  irplib_ksigma_clip(img,1,1,
96  cpl_image_get_size_x(img),
97  cpl_image_get_size_y(img),
98  nclip,kappa,tolerance,&mean,&stdev);
99  cpl_msg_info(cpl_func,"Ima %d mean level: %g",i+1,mean);
100  pval[i]=mean;
101  }
102 
103 
104  return levels;
105 }
106 
107 /*-------------------------------------------------------------------------*/
115 /*--------------------------------------------------------------------------*/
116 static cpl_error_code
117 irplib_imagelist_subtract_values(cpl_imagelist** iml, cpl_vector* values)
118 {
119 
120  int size=0;
121  int i=0;
122  double* pval=NULL;
123 
124  size=cpl_imagelist_get_size(*iml);
125  pval=cpl_vector_get_data(values);
126 
127  for(i=0;i<size;i++) {
128  cpl_image* img=cpl_imagelist_get(*iml,i);
129  cpl_image_subtract_scalar(img,pval[i]);
130  cpl_imagelist_set(*iml,img,i);
131  }
132 
133  return cpl_error_get_code();
134 }
135 
136 /*---------------------------------------------------------------------------*/
149 /*---------------------------------------------------------------------------*/
150 static double
151 irplib_vector_ksigma(cpl_vector *values,
152  const double klow, const double khigh, int kiter)
153 {
154  double mean /*= 0.0*/; /* Comment out to suppress cppcheck warning. */
155  double sigma = 0.0;
156  double *data = cpl_vector_get_data(values);
157  int n = cpl_vector_get_size(values);
158  int ngood = n;
159  int i;
160 
161  /*
162  * At first iteration the mean is taken as the median, and the
163  * standard deviation relative to this value is computed.
164  */
165 
166  mean = cpl_vector_get_median(values);
167 
168  for (i = 0; i < n; i++) {
169  sigma += (mean - data[i]) * (mean - data[i]);
170  }
171  sigma = sqrt(sigma / (n - 1));
172 
173  while (kiter) {
174  cpl_vector *accepted;
175  int count = 0;
176  for (i = 0; i < ngood; i++) {
177  if (data[i]-mean < khigh*sigma && mean-data[i] < klow*sigma) {
178  data[count] = data[i];
179  ++count;
180  }
181  }
182 
183  if (count == 0) // This cannot happen at first iteration.
184  break; // So we can break: we have already computed a mean.
185 
186  /*
187  * The mean must be computed even if no element was rejected
188  * (count == ngood), because at first iteration median instead
189  * of mean was computed.
190  */
191 
192  accepted = cpl_vector_wrap(count, data);
193  mean = cpl_vector_get_mean(accepted);
194  if(count>1) {
195  sigma = cpl_vector_get_stdev(accepted);
196  }
197  cpl_vector_unwrap(accepted);
198 
199  if (count == ngood) {
200  break;
201  }
202  ngood = count;
203  --kiter;
204  }
205 
206  return mean;
207 }
208 
209 
228 static cpl_image *
229 irplib_imagelist_ksigma_stack(const cpl_imagelist *imlist,
230  double klow, double khigh, int kiter)
231 {
232  int ni, nx, ny, npix;
233  cpl_image *out_ima=NULL;
234  cpl_imagelist *loc_iml=NULL;
235  double *pout_ima=NULL;
236  cpl_image *image=NULL;
237  const double **data=NULL;
238  double *med=NULL;
239  cpl_vector *time_line=NULL;
240 
241  double *ptime_line=NULL;
242  int i, j;
243  double mean_of_medians=0;
244 
245  cpl_error_ensure(imlist != NULL, CPL_ERROR_NULL_INPUT, return(out_ima),
246  "Null input image list");
247 
248  ni = cpl_imagelist_get_size(imlist);
249  loc_iml = cpl_imagelist_duplicate(imlist);
250  image = cpl_imagelist_get(loc_iml, 0);
251  nx = cpl_image_get_size_x(image);
252  ny = cpl_image_get_size_y(image);
253  npix = nx * ny;
254 
255  out_ima = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
256  pout_ima = cpl_image_get_data_double(out_ima);
257 
258  time_line = cpl_vector_new(ni);
259 
260  ptime_line = cpl_vector_get_data(time_line);
261 
262  data = cpl_calloc(sizeof(double *), ni);
263  med = cpl_calloc(sizeof(double), ni);
264 
265  for (i = 0; i < ni; i++) {
266  image = cpl_imagelist_get(loc_iml, i);
267  med[i]=cpl_image_get_median(image);
268  cpl_image_subtract_scalar(image,med[i]);
269  data[i] = cpl_image_get_data_double(image);
270  mean_of_medians+=med[i];
271  }
272  mean_of_medians/=ni;
273 
274  for (i = 0; i < npix; i++) {
275  for (j = 0; j < ni; j++) {
276  ptime_line[j] = data[j][i];
277  }
278  pout_ima[i] = irplib_vector_ksigma(time_line, klow, khigh, kiter);
279  }
280 
281  cpl_image_add_scalar(out_ima,mean_of_medians);
282 
283 
284  cpl_free(data);
285  cpl_free(med);
286  cpl_vector_delete(time_line);
287  cpl_imagelist_delete(loc_iml);
288 
289  return out_ima;
290 
291 }
292 
293 
294 
295 
296 /*-------------------------------------------------------------------------*/
308 /*--------------------------------------------------------------------------*/
309 cpl_image*
310 irplib_mkmaster_mean(cpl_imagelist* images,const double kappa, const int nclip, const double tolerance,const double klow,const double khigh,const int niter)
311 {
312 
313  cpl_image* master=NULL;
314  cpl_vector* levels=NULL;
315  double mean=0;
316  cpl_imagelist* iml=NULL;
317 
318  cpl_msg_info(cpl_func,"method mean");
319  iml=cpl_imagelist_duplicate(images);
320  levels=irplib_imagelist_get_clean_mean_levels(iml,kappa,nclip,tolerance);
321  mean=cpl_vector_get_mean(levels);
322  cpl_msg_info(cpl_func,"Master mean level: %g",mean);
323 
324  irplib_imagelist_subtract_values(&iml,levels);
325 
326  master = irplib_imagelist_ksigma_stack(iml,klow,khigh,niter);
327  cpl_image_add_scalar(master,mean);
328 
329  cpl_vector_delete(levels);
330  cpl_imagelist_delete(iml);
331  return master;
332 
333 }
334 
335 /*-------------------------------------------------------------------------*/
347 /*--------------------------------------------------------------------------*/
348 cpl_image*
349 irplib_mkmaster_median(cpl_imagelist* images,const double kappa, const int nclip, const double tolerance)
350 {
351 
352  cpl_image* master=NULL;
353  cpl_vector* levels=NULL;
354  double mean=0;
355  cpl_imagelist* iml=NULL;
356 
357  cpl_msg_info(cpl_func,"method median");
358  iml=cpl_imagelist_duplicate(images);
359  levels=irplib_imagelist_get_clean_mean_levels(iml,kappa,nclip,tolerance);
360 
361  mean=cpl_vector_get_mean(levels);
362  cpl_msg_info(cpl_func,"Master mean level: %g",mean);
363  irplib_imagelist_subtract_values(&iml,levels);
364 
365  master = cpl_imagelist_collapse_median_create(iml);
366 
367  cpl_image_add_scalar(master,mean);
368 
369  cpl_vector_delete(levels);
370  cpl_imagelist_delete(iml);
371 
372  return master;
373 
374 }
375 
376 /* Work in progress */
377 static cpl_error_code
378 irplib_mkmaster_dark_qc(const cpl_imagelist* raw_images,
379  cpl_imagelist* preproc_images,
380  const cpl_parameterlist* parameters,
381  const int pr_num_x, const int pr_num_y,
382  const int pr_box_sx, const int pr_box_sy, const char* recipe_id,
383  cpl_table* qclog) {
384 
385  cpl_ensure_code(qclog !=NULL, CPL_ERROR_NULL_INPUT);
386  cpl_ensure_code(recipe_id !=NULL, CPL_ERROR_NULL_INPUT);
387  cpl_ensure_code(parameters !=NULL, CPL_ERROR_NULL_INPUT);
388 
389  if (pr_num_x != 0 && pr_num_y != 0 && pr_box_sx != 0 && pr_box_sy != 0) {
390  int i;
391  for (i = 0; i < cpl_imagelist_get_size(raw_images); i++) {
392  cpl_image* current_dark = cpl_image_duplicate(
393  cpl_imagelist_get_const(preproc_images, i));
394  cpl_msg_info(cpl_func, "Calculating QC parameters on raw dark frame %d",
395  i);
396  /* Here To be defined more general way to qc-log */
397  /* UVES specific stuff: may be this function should not be put in irplib
398  irplib_mdark_region_qc(current_dark, parameters, raw_images, recipe_id,qclog);
399  */
400  /* FIXME: still safe if irplib_mdark_region_qc is commented in? */
401  cpl_image_delete(current_dark);
402  }
403  }
404  return cpl_error_get_code();
405 }
406 
407 /*-------------------------------------------------------------------------*/
417 /*-------------------------------------------------------------------------*/
418 static double
419 irplib_head_get_exptime(const cpl_propertylist * plist) {
420  double result = 0; /* Conversion from electrons to ADUs */
421 
422  result=cpl_propertylist_get_double(plist, "EXPTIME");
423  cpl_ensure_code(result >= 0, CPL_ERROR_ILLEGAL_OUTPUT);
424 
425  return result;
426 }
427 
428 /*-------------------------------------------------------------------------*/
436 /*-------------------------------------------------------------------------*/
437 static cpl_error_code
438 irplib_head_set_exptime(cpl_propertylist *plist, double exptime)
439 {
440  cpl_propertylist_update_double(plist, "EXPTIME", exptime);
441  cpl_propertylist_set_comment(plist, "EXPTIME", "Total integration time");
442 
443  return cpl_error_get_code();
444 }
445 
446 static cpl_imagelist*
447 irplib_mkmaster_dark_fill_imagelist(const cpl_imagelist* raw_images,
448  cpl_propertylist** raw_headers, const cpl_image* master_bias,
449  double* mean_exptime) {
450  /* First process each input image and store the results in a
451  new image list */
452 
453  cpl_imagelist* preproc_images = NULL;
454  int i = 0;
455  double min_exptime = 0;
456  double max_exptime = 0;
457 
458  preproc_images = cpl_imagelist_new();
459  for (i = 0; i < cpl_imagelist_get_size(raw_images); i++) {
460  double exposure_time = 0.0;
461  cpl_image* current_dark = NULL;
462  const cpl_propertylist *current_header;
463 
464  current_dark = cpl_image_duplicate(cpl_imagelist_get_const(raw_images, i));
465  current_header = raw_headers[i];
466 
467  /* Subtract master bias */
468  if (master_bias != NULL) {
469  cpl_msg_info(cpl_func, "Subtracting master bias");
470  cpl_image_subtract(current_dark, master_bias);
471  } else {
472  cpl_msg_info(cpl_func, "Skipping bias subtraction");
473  }
474 
475  exposure_time = irplib_head_get_exptime(current_header);
476 
477  /* Initialize/update min/max exposure time*/
478  if (i == 0 || exposure_time < min_exptime) {
479  min_exptime = exposure_time;
480  }
481  if (i == 0 || exposure_time > max_exptime) {
482  max_exptime = exposure_time;
483  }
484 
485  /* Do not normalize to unit exposure time */
486  /* If this is uncommented, then remember to also calculate the
487  correct master dark exposure time below.
488  irplib_msg("Normalizing from %f s to unit exposure time", exposure_time);
489  check( cpl_image_divide_scalar(current_dark, exposure_time),
490  "Error normalizing dark frame"); */
491 
492  /* Append to imagelist */
493  cpl_imagelist_set(preproc_images, current_dark, i);
494 
495  /* Don't deallocate the image. It will be deallocated when
496  the image list is deallocated */
497  current_dark = NULL;
498  }
499 
500 
501  /* Check exposure times */
502  cpl_msg_info(cpl_func,
503  "Exposure times range from %e s to %e s (%e %% variation)", min_exptime,
504  max_exptime, 100 * (max_exptime - min_exptime) / min_exptime);
505 
506  if ((max_exptime - min_exptime) / min_exptime > .001) {
507  cpl_msg_warning(cpl_func, "Exposure times differ by %e %%",
508  100 * (max_exptime - min_exptime) / min_exptime);
509  }
510 
511  /* compute correct exposure time */
512  *mean_exptime=0.5 * (max_exptime + min_exptime);
513  return preproc_images;
514 }
515 
516 
517 cpl_image *
518 irplib_mdark_process_chip(const cpl_imagelist *raw_images,
519  cpl_propertylist **raw_headers, const cpl_image *master_bias,
520  cpl_propertylist *mdark_header, const cpl_parameterlist *parameters,
521  const char* recipe_id, cpl_table* qclog, const int do_qc,
522  const char* STACK_METHOD, const double STACK_KLOW, const double STACK_KHIGH,
523  const int STACK_NITER,
524  const int pr_num_x, const int pr_num_y,
525  const int pr_box_sx, const int pr_box_sy) {
526  cpl_image *master_dark = NULL; /* Result */
527  cpl_image *current_dark = NULL;
528  cpl_imagelist *preproc_images = NULL;
529  double mean_exptime = 0;
530 
531  /* First process each input image and store the results in a
532  new image list */
533  preproc_images = irplib_mkmaster_dark_fill_imagelist(raw_images, raw_headers,
534  master_bias, &mean_exptime);
535  if (do_qc) {
536  /* Here we should compute QC but a a better way to log it is TBD */
537  irplib_mkmaster_dark_qc(raw_images, preproc_images, parameters, pr_num_x,
538  pr_num_y, pr_box_sx, pr_box_sy, recipe_id, qclog);
539 
540  }
541  /* Get median stack of input darks */
542  if (strcmp(STACK_METHOD, "MEDIAN") == 0) {
543  cpl_msg_info(cpl_func, "Calculating stack median");
544  master_dark = cpl_imagelist_collapse_median_create(preproc_images);
545  } else {
546  cpl_msg_info(cpl_func, "Calculating stack mean");
547  master_dark = irplib_imagelist_ksigma_stack(preproc_images, STACK_KLOW,
548  STACK_KHIGH, STACK_NITER);
549 
550  }
551  irplib_head_set_exptime(mdark_header, mean_exptime );
552 
553  cpl_image_delete(current_dark);
554  cpl_imagelist_delete(preproc_images);
555  if (cpl_error_get_code() != CPL_ERROR_NONE) {
556  cpl_image_delete(master_dark);
557  }
558 
559  return master_dark;
560 }
561 
cpl_image * irplib_mkmaster_median(cpl_imagelist *images, const double kappa, const int nclip, const double tolerance)
Computes master frame by clean stack median of the input imagelist.
cpl_image * irplib_mkmaster_mean(cpl_imagelist *images, const double kappa, const int nclip, const double tolerance, const double klow, const double khigh, const int niter)
Computes master frame by clean stack mean of the input imagelist.