GIRAFFE Pipeline Reference Manual

gidark.c
1 /*
2  * This file is part of the GIRAFFE Pipeline
3  * Copyright (C) 2002-2019 European Southern Observatory
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 
24 #include <string.h>
25 #include <math.h>
26 
27 #include <cxlist.h>
28 
29 #include "gialias.h"
30 #include "giarray.h"
31 #include "girange.h"
32 #include "giwindow.h"
33 #include "gidark.h"
34 
35 
44 inline static cxint
45 _giraffe_halfrange_mode(cxdouble *mode, cxdouble* array, cxsize* size,
46  cxdouble portion, cxdouble epsilon)
47 {
48 
49  cxint status = 0;
50 
51  register cxsize i = 0;
52 
53  cxsize ndata = 0;
54  cxsize _size = *size;
55 
56  cxdouble tiny = CX_MAXDOUBLE;
57 
58 
59  for (i = 0; i < _size - 1; i++) {
60 
61  cxdouble t = array[i + 1] - array[i];
62 
63  if (t <= 0.) {
64  continue;
65  }
66 
67  if (t < tiny) {
68  tiny = t;
69  }
70  }
71 
72  tiny /= 2.;
73 
74  if (tiny <= epsilon) {
75  tiny = epsilon;
76  // return -1;
77  }
78 
79  if (_size < 3) {
80 
81  cxdouble _mode = 0.;
82 
83 
84  status = 0;
85 
86  switch (_size) {
87  case 2:
88  _mode = (array[0] + array[1]) / 2.;
89  break;
90 
91  case 1:
92  _mode = array[0];
93  break;
94 
95  default:
96  status = -2;
97  break;
98  }
99 
100  *mode = _mode;
101  return status;
102 
103  }
104  else {
105 
106  cxsize count = 0;
107 
108  cxdouble iwidth = array[_size - 1] - array[0];
109  cxdouble iweps = 0.;
110 
111  cx_list* intervals = NULL;
112 
113  GiRange* interval = NULL;
114 
115 
116  if (iwidth <= epsilon) {
117  *mode = giraffe_array_mean(array, _size);
118  return 0;
119  }
120 
121  iwidth *= portion;
122  iweps = iwidth + tiny;
123 
124  intervals = cx_list_new();
125 
126  i = 0;
127  while (i < _size) {
128 
129  register cxsize j = 0;
130  register cxssize k = -1;
131 
132  cxsize nvalues = 0;
133 
134  GiRange* _interval = giraffe_range_create(array[i] - tiny,
135  array[i] + iweps);
136 
137 
138  for (j = 0; j < _size; j++) {
139 
140  register cxdouble value = array[j];
141 
142 
143  if (value >= giraffe_range_get_max(_interval)) {
144  break;
145  }
146 
147  if (value <= giraffe_range_get_min(_interval)) {
148  continue;
149  }
150 
151  if (k < 0) {
152  giraffe_range_set_min(_interval, value - tiny);
153  k = j;
154  }
155 
156  }
157 
158  giraffe_range_set_max(_interval, array[j - 1] + tiny);
159  nvalues = j - k;
160 
161  if (nvalues > count) {
162 
163  cx_list_iterator position = cx_list_begin(intervals);
164  cx_list_const_iterator last = cx_list_end(intervals);
165 
166  count = nvalues;
167 
168  while (position != last) {
169  position =
170  cx_list_erase(intervals, position,
171  (cx_free_func)giraffe_range_delete);
172  }
173  cx_list_clear(intervals);
174 
175  cx_list_push_back(intervals, _interval);
176  _interval = NULL;
177 
178  }
179  else if (nvalues == count) {
180 
181  cx_list_push_back(intervals, _interval);
182  _interval = NULL;
183 
184  }
185  else {
186 
187  giraffe_range_delete(_interval);
188  _interval = NULL;
189 
190  }
191 
192  ++i;
193 
194  }
195 
196  if (cx_list_size(intervals) == 1) {
197 
198  GiRange* _interval = cx_list_front(intervals);
199 
200  cxdouble minimum = giraffe_range_get_min(_interval);
201  cxdouble maximum = giraffe_range_get_max(_interval);
202 
203  interval = giraffe_range_create(minimum, maximum);
204 
205  }
206  else {
207 
208  cxdouble minimum = 0.;
209  cxdouble maximum = 0.;
210 
211  cx_list_iterator position = cx_list_begin(intervals);
212 
213  cx_list_const_iterator last = cx_list_end(intervals);
214 
215 
216  iwidth = CX_MAXDOUBLE;
217 
218 
219  /*
220  * Find smallest intervals
221  */
222 
223  while (position != last) {
224 
225  GiRange* _interval = cx_list_get(intervals, position);
226 
227  cxdouble t = giraffe_range_get_max(_interval) -
228  giraffe_range_get_min(_interval);
229 
230 
231  if (t <= 0.) {
232  continue;
233  }
234 
235  if (t < iwidth) {
236  iwidth = t;
237  }
238 
239  position = cx_list_next(intervals, position);
240 
241  }
242 
243  iwidth += tiny;
244 
245 
246  /*
247  * Remove intervals with a larger width than iwidth.
248  */
249 
250  position = cx_list_begin(intervals);
251  last = cx_list_end(intervals);
252 
253  while (position != last) {
254 
255  GiRange* _interval = cx_list_get(intervals, position);
256 
257  cxdouble t = giraffe_range_get_max(_interval) -
258  giraffe_range_get_min(_interval);
259 
260 
261  if (t >= iwidth) {
262  position =
263  cx_list_erase(intervals, position,
264  (cx_free_func)giraffe_range_delete);
265  }
266  else {
267  position = cx_list_next(intervals, position);
268  }
269 
270  }
271 
272  minimum = giraffe_range_get_min(cx_list_front(intervals));
273  maximum = giraffe_range_get_max(cx_list_back(intervals));
274 
275  interval = giraffe_range_create(minimum, maximum);
276 
277  }
278 
279  cx_list_destroy(intervals, (cx_free_func)giraffe_range_delete);
280  intervals = NULL;
281 
282 
283  /*
284  * Discard data outside the intervals
285  */
286 
287  ndata = 0;
288 
289  for (i = 0; i < _size; i++) {
290 
291  if (array[i] < giraffe_range_get_min(interval)) {
292  continue;
293  }
294 
295  if (array[i] > giraffe_range_get_max(interval)) {
296  break;
297  }
298 
299  array[ndata++] = array[i];
300 
301  }
302 
303  giraffe_range_delete(interval);
304  interval = NULL;
305 
306 
307  if (ndata == _size) {
308 
309  cxdouble start = array[1] - array[0];
310  cxdouble end = array[ndata - 1] - array[ndata - 2];
311 
312 
313  if (fabs(start - end) < epsilon) {
314 
315  /* Remove the first and the last value */
316  ndata -=2;
317  memmove(array, &array[1], ndata * sizeof(cxdouble));
318 
319  }
320  else {
321 
322  if (start < end) {
323 
324  /* Remove last value */
325  --ndata;
326 
327  }
328  else {
329 
330  /* Remove first value */
331  --ndata;
332  memmove(array, &array[1], ndata * sizeof(cxdouble));
333 
334  }
335 
336  }
337 
338  }
339 
340  *size = ndata;
341 
342  status = _giraffe_halfrange_mode(mode, array, size, portion, epsilon);
343 
344  }
345 
346  return status;
347 
348 }
349 
350 
351 inline static cxdouble
352 _giraffe_dark_compute_mode(const cpl_image* image, const cpl_image* bpixel)
353 {
354 
355  register cxsize i = 0;
356 
357  cxint status = 0;
358 
359  cxsize ndata = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
360  cxsize count = 0;
361  cxsize nbuffer = 0;
362 
363  const cxdouble* _image = cpl_image_get_data_double_const(image);
364 
365  cxdouble mode = 0.;
366  cxdouble delta = 0.;
367  cxdouble* buffer = NULL;
368  cxdouble* sorted_image = NULL;
369 
370 
371  cx_assert(cpl_image_get_type(image) == CPL_TYPE_DOUBLE);
372 
373  sorted_image = cx_calloc(ndata, sizeof(cxdouble));
374  memcpy(sorted_image, _image, ndata * sizeof(cxdouble));
375 
376  if (bpixel != NULL) {
377 
378  const cxint* _bpixel = cpl_image_get_data_int_const(bpixel);
379 
380 
381  for (i = 0; i < ndata; i++) {
382 
383  if (_bpixel[i] == GI_BPIX_OK) {
384  sorted_image[count++] = _image[i];
385  }
386 
387  }
388 
389  }
390  else {
391  count = ndata;
392  }
393 
394  status = giraffe_array_sort(sorted_image, count);
395 
396  if (status != 0) {
397  return 0.;
398  }
399 
400 
401  buffer = cx_calloc(count, sizeof(cxdouble));
402 
403  for (i = 0; i < count; i += 1000) {
404  buffer[nbuffer++] = sorted_image[i];
405  }
406 
407 
408  // FIXME: Check whether _giraffe_halfrange_mode() needs to update the
409  // size of buffer on return!
410 
411  status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.1, 1.e-9);
412 
413  delta = CX_MIN(mode / 10.,
414  (sorted_image[count - 1] - sorted_image[0]) / 2.);
415  nbuffer = count;
416 
417  while ((nbuffer > 50000) && (delta > 1.e-6)) {
418 
419  register cxsize j = 0;
420 
421  for (i = 0; i < count; i++) {
422 
423  if (sorted_image[i] < (mode - delta)) {
424  continue;
425  }
426 
427  if (sorted_image[i] > (mode + delta)) {
428  break;
429  }
430 
431  buffer[j++] = sorted_image[i];
432 
433  }
434 
435  delta /= 2.;
436 
437  if (j > 0) {
438  nbuffer = j;
439  }
440 
441  }
442 
443  if (delta > 1.e-6) {
444  status = _giraffe_halfrange_mode(&mode, buffer, &nbuffer, 0.5, 1.e-9);
445  }
446  else {
447  mode = giraffe_array_mean(buffer, nbuffer);
448  }
449 
450  cx_free(buffer);
451  buffer = NULL;
452 
453  cx_free(sorted_image);
454  sorted_image = NULL;
455 
456  return mode;
457 
458 }
459 
460 
477 cxint
478 giraffe_subtract_dark(GiImage* image, const GiImage* dark,
479  const GiImage* bpixel, GiDarkResults* data,
480  const GiDarkConfig* config)
481 {
482 
483  cxbool crop = FALSE;
484 
485  cxint nx = 0;
486  cxint ny = 0;
487 
488  cxdouble exptime = 0.;
489  cxdouble darktime = 0.;
490  cxdouble dark_max = 0.;
491  cxdouble dark_mode = 0.;
492  cxdouble dark_value = 0.;
493  cxdouble timescale = 1.;
494 
495  cpl_propertylist* properties = NULL;
496 
497  const cpl_image* _dark = NULL;
498  const cpl_image* _bpixel = NULL;
499 
500  cpl_image* _image = NULL;
501 
502 
503  if ((image == NULL) || (dark == NULL)) {
504  return -1;
505  }
506 
507  if (config == NULL) {
508  return -2;
509  }
510 
511  _image = giraffe_image_get(image);
512  _dark = giraffe_image_get(dark);
513 
514  nx = cpl_image_get_size_y(_image);
515  ny = cpl_image_get_size_x(_image);
516 
517  if ((nx != cpl_image_get_size_y(_dark)) ||
518  (ny != cpl_image_get_size_x(_dark))) {
519  return -3;
520  }
521 
522  if (bpixel != NULL) {
523 
524  GiWindow area = {1, 1, ny, nx};
525 
526  properties = giraffe_image_get_properties(bpixel);
527  _bpixel = giraffe_image_get(bpixel);
528 
529  if (cpl_propertylist_has(properties, GIALIAS_PRSCX) == TRUE) {
530  area.x0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCX);
531  crop = TRUE;
532  }
533 
534  if (cpl_propertylist_has(properties, GIALIAS_PRSCY) == TRUE) {
535  area.y0 += cpl_propertylist_get_int(properties, GIALIAS_PRSCY);
536  crop = TRUE;
537  }
538 
539  if (cpl_propertylist_has(properties, GIALIAS_OVSCX) == TRUE) {
540  area.x1 = cpl_image_get_size_x(_bpixel) -
541  cpl_propertylist_get_int(properties, GIALIAS_OVSCX);
542  crop = TRUE;
543  }
544 
545  if (cpl_propertylist_has(properties, GIALIAS_OVSCY) == TRUE) {
546  area.y1 = cpl_image_get_size_y(_bpixel) -
547  cpl_propertylist_get_int(properties, GIALIAS_OVSCY);
548  crop = TRUE;
549  }
550 
551  if (crop == TRUE) {
552  _bpixel = cpl_image_extract(_bpixel, area.x0, area.y0,
553  area.x1, area.y1);
554  }
555 
556  }
557 
558 
559  /*
560  * Get the dark current time from the input image and the dark.
561  */
562 
563  properties = giraffe_image_get_properties(image);
564  cx_assert(properties != NULL);
565 
566  if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
567  return 1;
568  }
569  else {
570  exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
571  }
572 
573  properties = giraffe_image_get_properties(dark);
574  cx_assert(properties != NULL);
575 
576  if (cpl_propertylist_has(properties, GIALIAS_EXPTIME) == FALSE) {
577  return 1;
578  }
579  else {
580  darktime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
581  }
582 
583 
584  /*
585  * Dark current scale factor
586  */
587 
588  timescale = exptime / darktime;
589 
590 
591  /*
592  * Compute mode and maximum of the dark.
593  */
594 
595  dark_max = cpl_image_get_max(_dark) * timescale;
596  dark_mode = _giraffe_dark_compute_mode(_dark, _bpixel) * timescale;
597 
598 
599  /*
600  * Correct the input image for the dark current
601  */
602 
603  switch (config->method) {
604  case GIDARK_METHOD_UNIFORM:
605 
606  if (dark_max < config->threshold) {
607 
608  /* No dark subtraction */
609 
610  dark_value = 0.;
611 
612  }
613  else {
614 
615  dark_value = dark_mode;
616  cpl_image_subtract_scalar(_image, dark_value);
617 
618  }
619  break;
620 
621  case GIDARK_METHOD_ZMASTER:
622  {
623 
624  register cxint i = 0;
625 
626  cxdouble* pximage = NULL;
627  cxdouble* pxdark = NULL;
628 
629  cpl_image* scaled_dark = cpl_image_duplicate(_dark);
630 
631  pximage = cpl_image_get_data_double(_image);
632  pxdark = cpl_image_get_data_double(scaled_dark);
633 
634  if (_bpixel == NULL) {
635 
636  register cxint j = 0;
637  register cxint n = nx * ny;
638 
639  for (j = 0; j < n; j++) {
640 
641  pxdark[j] *= timescale;
642 
643  if (pxdark[j] < config->threshold) {
644  pxdark[j] = dark_mode;
645  }
646 
647  }
648 
649  }
650  else {
651 
652  register cxint j = 0;
653  register cxint n = nx * ny;
654 
655  const cxint* pxmask = cpl_image_get_data_int_const(_bpixel);
656 
657 
658  for (j = 0; j < n; j++) {
659 
660  if ((pxmask[j] & GI_M_PIX_SET) == 0x0) {
661  pxdark[j] *= timescale;
662  }
663  else {
664  pxdark[j] = dark_mode;
665  }
666 
667  }
668 
669  }
670 
671 
672  for (i = 0; i < nx; i++) {
673 
674  register cxint j = 0;
675  register cxint base = i * ny;
676 
677  for (j = 0; j < ny; j++) {
678 
679  register cxint offset = base + j;
680 
681  pximage[offset] -= pxdark[offset];
682 
683  }
684 
685  }
686 
687  dark_mode = _giraffe_dark_compute_mode(scaled_dark, _bpixel);
688  dark_value = dark_mode;
689 
690  cpl_image_delete(scaled_dark);
691  scaled_dark = NULL;
692 
693  }
694  break;
695 
696  case GIDARK_METHOD_MASTER:
697  default:
698  {
699 
700  register cxint i = 0;
701 
702  const cxdouble* pxdark = NULL;
703 
704  cxdouble* pximage = NULL;
705 
706  pximage = cpl_image_get_data_double(_image);
707  pxdark = cpl_image_get_data_double_const(_dark);
708 
709  for (i = 0; i < nx; i++) {
710 
711  register cxint j = 0;
712  register cxint base = i * ny;
713 
714  for (j = 0; j < ny; j++) {
715 
716  register cxint offset = base + j;
717 
718  pximage[offset] -= pxdark[offset] * timescale;
719 
720  }
721 
722  }
723  }
724  break;
725 
726  }
727 
728 
729  /*
730  * Update the properties of the corrected image.
731  */
732 
733  properties = giraffe_image_get_properties(image);
734 
735  cpl_propertylist_update_double(properties, GIALIAS_DARKVALUE,
736  dark_value / timescale);
737  cpl_propertylist_set_comment(properties, GIALIAS_DARKVALUE,
738  "Used dark current [ADU/s]");
739  cpl_propertylist_update_double(properties, GIALIAS_DARKEXPECT,
740  dark_mode / timescale);
741  cpl_propertylist_set_comment(properties, GIALIAS_DARKEXPECT,
742  "Expected dark current [ADU/s]");
743 
744 
745  /*
746  * Update dark results data
747  */
748 
749  if (data != NULL) {
750  data->value = dark_value;
751  data->expected = dark_mode;
752  data->mode = dark_mode / timescale;
753  data->maximum = dark_max / timescale;
754  }
755 
756 
757  /*
758  * Cleanup
759  */
760 
761  if (crop == TRUE) {
762  cpl_image_delete((cpl_image*)_bpixel);
763  _bpixel = NULL;
764  }
765 
766 
767  return 0;
768 
769 }
cxint giraffe_array_sort(cxdouble *array, cxsize size)
Sorts an array in ascending order.
Definition: giarray.c:169
cxint giraffe_subtract_dark(GiImage *image, const GiImage *dark, const GiImage *bpixel, GiDarkResults *data, const GiDarkConfig *config)
Subtract the dark current from a bias corrected image.
Definition: gidark.c:478
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
Definition: giimage.c:282
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
Definition: giimage.c:218
GiRange * giraffe_range_create(cxdouble min, cxdouble max)
Creates a new range from the given minimum and maximum values.
Definition: girange.c:83
void giraffe_range_set_min(GiRange *self, cxdouble min)
Set the minimum of a range.
Definition: girange.c:144
void giraffe_range_delete(GiRange *self)
Destroys a range object.
Definition: girange.c:118
cxdouble giraffe_range_get_min(const GiRange *const self)
Get the minimum of a range.
Definition: girange.c:167
cxdouble giraffe_range_get_max(const GiRange *const self)
Get the maximum of a range.
Definition: girange.c:213
void giraffe_range_set_max(GiRange *self, cxdouble max)
Set the maximum of a range.
Definition: girange.c:190

This file is part of the GIRAFFE Pipeline Reference Manual 2.16.10.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Dec 15 2022 21:18:51 by doxygen 1.9.1 written by Dimitri van Heesch, © 1997-2004