ERIS Pipeline Reference Manual 1.8.15
eris_nix_detector.c
1/* $Id$
2 *
3 * This file is part of the ERIS/NIX Pipeline
4 * Copyright (C) 2017 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 02110-1301 USA
19 */
20
21 /*
22 * $Author$
23 * $Date$
24 * $Rev$
25 */
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30
31#ifdef _OPENMP
32#include <omp.h>
33#endif
34
35/*-----------------------------------------------------------------------------
36 Includes
37 -----------------------------------------------------------------------------*/
38
39#include "eris_nix_detector.h"
40
41#include "eris_nix_casu_utils.h"
42#include "eris_nix_dfs.h"
43
44#include <casu_mods.h>
45#include <hdrl.h>
46#include <libgen.h>
47#include <math.h>
48#include <string.h>
49#include <time.h>
50
51/*----------------------------------------------------------------------------*/
55/*----------------------------------------------------------------------------*/
56
57inline static
58void engl_lin_correct_(double *,
59 const cpl_size,
60 const double *,
61 const cpl_binary,
62 const double,
63 cpl_binary *,
64 const int) CPL_ATTR_NONNULL;
65
66inline static
67double engl_lin_find_(const double,
68 double,
69 double,
70 const cpl_size,
71 const double *,
72 double *) CPL_ATTR_NONNULL;
73
76/*----------------------------------------------------------------------------*/
99/*----------------------------------------------------------------------------*/
100
101eris_nix_samples * end_calculate_samples(const cpl_image * start_intensity,
102 const cpl_image * ramp_intensity,
103 cpl_size nr,
104 const double dit,
105 const cpl_image * f) {
106
107 if (cpl_error_get_code() != CPL_ERROR_NONE) return NULL;
108
109 cpl_ensure(start_intensity, CPL_ERROR_NULL_INPUT, NULL);
110 cpl_ensure(ramp_intensity, CPL_ERROR_NULL_INPUT, NULL);
111 cpl_ensure(f, CPL_ERROR_NULL_INPUT, NULL);
112 cpl_ensure(nr > 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
113 cpl_ensure(dit > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
114
115 eris_nix_samples * result = cpl_calloc(1, sizeof(eris_nix_samples));
116 result->nr = nr;
117 result->samples = cpl_calloc(nr, sizeof(cpl_image *));
118 const double dt = dit / (float) (nr - 1);
119
120 /* first sample calculated from start_intensity */
121
122 result->samples[0] = cpl_image_multiply_scalar_create(f, -1.0);
123 cpl_image_add_scalar(result->samples[0], 1.0);
124 cpl_image_multiply(result->samples[0], start_intensity);
125 cpl_image_multiply_scalar(result->samples[0], dt);
126
127 /* subsequent (ramp) samples with slope from ramp_intensity, _relative_
128 to Vacca sample 1 (=sample 0 in struct); f drops out. */
129
130 for (cpl_size i = 2; i <= nr; i++) {
131 result->samples[i-1] = cpl_image_duplicate(ramp_intensity);
132 cpl_image_multiply_scalar(result->samples[i-1], (double) (i-1) * dt);
133 /* add sample 0 to give absolute value */
134 cpl_image_add(result->samples[i-1], result->samples[0]);
135 }
136
137 /* tidy up on error */
138
139 if (cpl_error_get_code() != CPL_ERROR_NONE) {
140 end_samples_delete(result);
141 result = NULL;
142 }
143 return result;
144}
145
146
147/*----------------------------------------------------------------------------*/
155/*----------------------------------------------------------------------------*/
156
157void end_samples_delete(eris_nix_samples * samples) {
158
159 if (samples) {
160 for (cpl_size i = 0; i < samples->nr; i++) {
161 cpl_image_delete(samples->samples[i]);
162 }
163 cpl_free(samples->samples);
164 cpl_free(samples);
165 }
166}
167
168
169/*----------------------------------------------------------------------------*/
207/*----------------------------------------------------------------------------*/
208
209cpl_error_code end_linearize_image(cpl_image * data,
210 const gain_linearity * gain_lin,
211 const cpl_size rot,
212 const cpl_size strx,
213 const cpl_size stry,
214 const cpl_size x_probe,
215 const cpl_size y_probe) {
216
217 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
218
219#ifdef _OPENMP
220 double time1, time2, time3;
221 time1 = omp_get_wtime();
222#else
223 clock_t time1, time2, time3;
224 time1 = clock();
225#endif
226
227 cpl_ensure_code(data, CPL_ERROR_NULL_INPUT);
228 cpl_ensure_code(gain_lin, CPL_ERROR_NULL_INPUT);
229 /* code assumes rot = 0 for now */
230 cpl_ensure_code(rot == 0, CPL_ERROR_UNSUPPORTED_MODE);
231
232 /* Get various parameters need for linearization */
233
234 const cpl_size fit_order = cpl_imagelist_get_size(gain_lin->
235 lin_coeffs);
236 const cpl_binary * fit_bpm = cpl_mask_get_data_const(gain_lin->bpm);
237
238 enu_check(cpl_error_get_code()==CPL_ERROR_NONE && fit_order > 1,
239 CPL_ERROR_INCOMPATIBLE_INPUT,
240 "linearization data in unexpected format");
241
242 /* sizes of linearity data and image */
243
244 cpl_size coeff_nx = cpl_image_get_size_x(cpl_imagelist_get_const(
245 gain_lin->lin_coeffs, 0));
246 cpl_size coeff_ny = cpl_image_get_size_y(cpl_imagelist_get_const(
247 gain_lin->lin_coeffs, 0));
248 const cpl_size nx = cpl_image_get_size_x(data);
249 const cpl_size ny = cpl_image_get_size_y(data);
250
251 /* check that the image data is double */
252 enu_check(cpl_image_get_type(data)==CPL_TYPE_DOUBLE,
253 CPL_ERROR_INCOMPATIBLE_INPUT, "image data is not double");
254
255 /* Get pointers to image data and bpm */
256
257 double * pdata = cpl_image_get_data_double(data);
258 cpl_binary * pbpm = cpl_mask_get_data(cpl_image_get_bpm(data));
259 const cpl_boolean do_info_msg = cpl_msg_get_level() <= CPL_MSG_INFO &&
260 (x_probe >= 0) && (y_probe >= 0);
261
262 enu_check(nx + strx - 1 <= coeff_nx, CPL_ERROR_UNSPECIFIED,
263 "Illegal X-windowing");
264 enu_check(ny + stry - 1 <= coeff_ny, CPL_ERROR_UNSPECIFIED,
265 "Illegal Y-windowing");
266
267 /* Loop through pixels */
268
269#ifdef _OPENMP
270 time2 = omp_get_wtime();
271#else
272 time2 = clock();
273#endif
274
275 if (strx == 1 && stry == 1 && coeff_nx == nx) {
276
277//#ifdef _OPENMP
278//#pragma omp parallel for
279//#endif
280 for (cpl_size ipos= 0 ; ipos < nx * ny ; ipos++) { /* pixel pos in image */
281 if (!pbpm[ipos]) { /* Skip rejected pixels */
282
283 const int debug = do_info_msg &&
284 (ipos % nx == x_probe) && (ipos / nx == y_probe);
285
286 /* Correct the good pixel */
287 engl_lin_correct_(pdata + ipos, fit_order, gain_lin
288 ->ordered_lin_coeffs + ipos * fit_order,
289 fit_bpm[ipos],
290 gain_lin->saturation_limit,
291 pbpm + ipos,
292 debug);
293
294
295 }
296 }
297 } else {
298 cpl_msg_info(cpl_func, "Windowing: %d %d %d %d", (int)strx, (int)stry,
299 (int)coeff_nx, (int)coeff_ny);
300
301//#ifdef _OPENMP
302//#pragma omp parallel for
303//#endif
304 for (cpl_size iy=0 ; iy < ny ; iy++) {
305 for (cpl_size ix=0 ; ix < nx ; ix++) {
306
307 /* pixel pos in image */
308 const cpl_size ipos = ix + iy * nx;
309
310 if (!pbpm[ipos]) { /* Skip rejected pixels */
311
312 /* pixel pos in linearity arrays, strx and stry are 1-based */
313 const cpl_size coeff_x = ix + strx - 1;
314 const cpl_size coeff_y = iy + stry - 1;
315 const cpl_size coeff_pos = coeff_x + coeff_y * coeff_nx;
316 const int debug = do_info_msg && (ix == x_probe) && (iy == y_probe);
317
318 /* Correct the good pixel */
319
320 engl_lin_correct_(pdata + ipos, fit_order, gain_lin
321 ->ordered_lin_coeffs + coeff_pos * fit_order,
322 fit_bpm[coeff_pos],
323 gain_lin->saturation_limit,
324 pbpm + ipos,
325 debug);
326
327
328 }
329 }
330 }
331 }
332
333#ifdef _OPENMP
334 time3 = omp_get_wtime();
335#else
336 time3 = clock();
337#endif
338
339#ifdef _OPENMP
340 cpl_msg_info(cpl_func, "end_linearize_image OPM setup %5.2e lin %5.2e",
341 time2-time1, time3-time2);
342#else
343 cpl_msg_info(cpl_func, "end_linearize_image setup %5.2e lin %5.2e",
344 (double)(time2-time1) / CLOCKS_PER_SEC,
345 (double)(time3-time2) / CLOCKS_PER_SEC);
346#endif
347
348cleanup:
349
350 return cpl_error_get_code();
351}
352
353
354/*----------------------------------------------------------------------------*/
370/*----------------------------------------------------------------------------*/
371
372cpl_image * end_uptheramp_reduce(eris_nix_samples * samples,
373 const double dit) {
374
375 if (cpl_error_get_code() != CPL_ERROR_NONE) return NULL;
376
377 cpl_ensure(samples, CPL_ERROR_NULL_INPUT, NULL);
378 cpl_ensure(samples->nr > 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
379 cpl_ensure(dit > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
380
381 /* initialize result to 0 */
382
383 cpl_image * result = cpl_image_new(
384 cpl_image_get_size_x(samples->samples[0]),
385 cpl_image_get_size_y(samples->samples[0]),
386 cpl_image_get_type(samples->samples[0]));
387
388 /* calculate result */
389
390 const cpl_size nr = samples->nr;
391 for (cpl_size i = 1; i <= nr && cpl_error_get_code()==CPL_ERROR_NONE;
392 i++) {
393
394 cpl_image * temp = cpl_image_multiply_scalar_create(
395 samples->samples[i-1],
396 (double)i - ((double)nr + 1.0) / 2.0);
397 cpl_image_add(result, temp);
398 cpl_image_delete(temp);
399 }
400 const double alpha = (double) (nr * (nr + 1)) * dit / 12.0;
401 cpl_image_divide_scalar(result, alpha);
402
403 /* tidy up if an error has occurred */
404
405 if (cpl_error_get_code() != CPL_ERROR_NONE) {
406 cpl_image_delete(result);
407 result = NULL;
408 }
409 return result;
410}
411
412
413/*----------------------------------------------------------------------------*/
441/*----------------------------------------------------------------------------*/
442
443hdrl_image *
444end_linearize_and_variance_detmon(const gain_linearity * gain_lin,
445 const master_dark * mdark,
446 const hdrl_image * himage,
447 const cpl_propertylist * plist,
448 const cpl_size x_probe,
449 const cpl_size y_probe) {
450
451 hdrl_image * self = NULL;
452 cpl_image * linear_data;
453 cpl_image * variance;
454
455 if (cpl_error_get_code() != CPL_ERROR_NONE) return NULL;
456
457 cpl_ensure(gain_lin, CPL_ERROR_NULL_INPUT, NULL);
458 cpl_ensure(mdark, CPL_ERROR_NULL_INPUT, NULL);
459
460 /* get the detector window used */
461
462 cpl_size nx = 0;
463 cpl_size ny = 0;
464 int rot = 0;
465 cpl_size strx = 0;
466 cpl_size stry = 0;
467 cpl_size nx_chip = 0;
468 cpl_size ny_chip = 0;
469 cpl_boolean windowed = 0;
471 &ny,
472 &rot,
473 &strx,
474 &stry,
475 &nx_chip,
476 &ny_chip,
477 &windowed,
478 plist);
479 enu_check_error_code("failed to read detector window information");
480
481 int probing = CPL_FALSE;
482 if (x_probe >= 1 && x_probe <= nx && y_probe >=1 && y_probe <= ny) {
483 probing = CPL_TRUE;
484 }
485
486 const char * det_mode = enu_get_det_mode(plist);
487 enu_check_error_code("failed to read detector mode information");
488 cpl_msg_info(cpl_func, "curname=%s rot=%d strx=%d stry=%d nx=%d ny=%d",
489 det_mode, (int)rot, (int)strx, (int)stry, (int)nx, (int)ny );
490
491 /* Create the new himage */
492 self = hdrl_image_duplicate(himage);
493 linear_data = hdrl_image_get_image(self);
494 variance = hdrl_image_get_error(self);
495
496 if (!strcmp(det_mode, "Double_RdRstRd")) {
497
498 /* CDS. Correlated Double Sampling for NACO.
499 In this mode the intensity is calculated from the difference
500 between 2 measurements at the start and end of the
501 integration. */
502
503 /* get the detector parameters required. */
504
505 double dit = enu_get_dit(plist);
506 const int ndit = cpl_propertylist_get_int(plist,
507 "ESO DET NDIT");
508 const int nr = 2; /* is this right? */
509
510 const double g = gain_lin->gain.data;
511 const double sigma_read = cpl_propertylist_get_double(
512 mdark->plist,
513 "ESO QC READ NOISE");
514
515 /* correct for non-linearity first by direct application of the
516 detmon curve correction. We cannot use the Vacca method for
517 this because detmon linerization info is not appropriate */
518
519 end_linearize_image(linear_data, gain_lin, rot, strx, stry,
520 x_probe, y_probe);
521
522 if (probing) {
523 int ignore;
524 double probe_v = cpl_image_get(linear_data, x_probe, y_probe,
525 &ignore);
526 cpl_msg_info(cpl_func, "linear_data %4.2e %d", probe_v,
527 ignore);
528 }
529
530 /* The Vacca formula for the variance works with intensity
531 measured in DN /sec. */
532
533 cpl_image_divide_scalar(linear_data, dit);
534
535 /* Calculate the variance in stages */
536
537 /* gain is in electrons/ADU.
538 read-noise is in electrons. */
539
540 /* the photon noise component of Vacca eqn 44 */
541
542 cpl_image_copy(variance, linear_data, 1, 1);
543
544 /* dt is the time taken to read the entire array - need to find
545 out this number */
546
547 /* actually, first set -ve numbers to zero as these make no
548 sense in terms of photon noise */
549
550 cpl_image_threshold(variance, 0.0, DBL_MAX, 0.0, DBL_MAX);
551 const double dt = 0.05;
552 cpl_image_multiply_scalar(variance,
553 (1.0 - dt * (nr * nr - 1) /
554 (3.0 * dit * nr)) /
555 (g * ndit * dit));
556 if (probing) {
557 cpl_msg_info(cpl_func, "photnoise factor %5.3e %d %5.3e %5.3e "
558 "%d %5.3e", dt, nr, dit, g, ndit,
559 (1.0 - dt * (nr * nr - 1) / (3.0 * dit * nr)) /
560 (g * ndit * dit));
561 }
562
563 /* add the read noise component of Vacca eqn 44 */
564
565 if (probing) {
566 cpl_msg_info(cpl_func, "readnoise comp %5.3e %5.3e %d %d"
567 "%5.3e% 5.3e", sigma_read, g, nr, ndit, dit,
568 2.0 * sigma_read * sigma_read /
569 (g * g * nr * ndit * dit * dit));
570 }
571 cpl_image_add_scalar(variance,
572 2.0 * sigma_read * sigma_read /
573 (g * g * nr * ndit * dit * dit));
574
575 /* make sure bad pixels are 0 */
576
577 cpl_image_fill_rejected(variance, 0.0);
578
579 } else if (!strcmp(det_mode, "SLOW_UP_THE_RAMP") ||
580 !strcmp(det_mode, "SLOW_GR_UTR")) {
581
582 cpl_msg_info(cpl_func, "slow gr utr %s", cpl_error_get_message());
583
584 /* Vacca et al. call this the 'Continuous Sampling Technique'.
585 In this mode the intensity is calculated by fitting a line
586 to a sequence of non-destructive reads carried out through
587 the DIT. */
588
589 /* get the detector parameters required */
590
591 double dit = enu_get_dit(plist);
592 const int ndit = cpl_propertylist_get_int(plist,
593 "ESO DET NDIT");
594 const int nr = cpl_propertylist_get_int(plist,
595 "ESO DET NDSAMPLES");
596 const double g = gain_lin->gain.data;
597 const double sigma_read = cpl_propertylist_get_double(
598 mdark->plist,
599 "ESO QC READ NOISE");
600
601 /* correct for non-linearity first by direct application of the
602 detmon curve correction. We cannot use the Vacca method for
603 this because detmon linerization info is derived from results
604 that have been processed by the controller and are not
605 raw counts */
606
607 end_linearize_image(linear_data, gain_lin, rot, strx, stry,
608 x_probe, y_probe);
609
610 /* The Vacca formula for the variance works with intensity
611 measured in DN /sec. */
612
613 cpl_image_divide_scalar(linear_data, dit);
614
615 /* Calculate the variance in stages */
616
617 /* gain is in electrons/ADU.
618 read-noise is in electrons. */
619
620 /* the photon noise component of Vacca eqn 56 */
621
622 cpl_image_copy(variance, linear_data, 1, 1);
623 cpl_image_multiply_scalar(variance, 1.2 * (nr*nr + 1) /
624 ((nr + 1) * nr * g * dit));
625
626 /* add the read noise component of Vacca eqn 56 */
627
628 cpl_image_add_scalar(variance,
629 12.0 * sigma_read * sigma_read *
630 (nr - 1) /
631 ((nr + 1) * nr * g * g * dit * dit));
632
633 /* Eqn 56 does not account for the NDIT repeats, so divide
634 the variance by NDIT now */
635
636 cpl_image_divide_scalar(variance, (double) ndit);
637
638 cpl_image_power(variance, 0.5);
639
640 /* ensure data and error masks are compatible to avoid potential
641 warning message from hdrl_create_image */
642
643 cpl_image_reject_from_mask(linear_data, cpl_image_get_bpm(variance));
644
645 } else if (!strcmp(det_mode, "FAST_UNCORR")) {
646
647 /* correct for non-linearity first by direct application of the
648 detmon curve correction */
649
650 end_linearize_image(linear_data, gain_lin, rot, strx, stry,
651 x_probe, y_probe);
652 if (probing) {
653 int ignore = 0;
654 double val = cpl_image_get(linear_data, x_probe, y_probe,
655 &ignore);
656 cpl_msg_info(cpl_func, "..eris_nix_detector probe (%d %d) "
657 "linearized_data v=%5.3e", (int)x_probe,
658 (int)y_probe, val);
659 }
660
661 /* Now calculate the variance ..
662 get the detector parameters required */
663
664 double dit = enu_get_dit(plist);
665 const double ndit = (double) cpl_propertylist_get_int(plist,
666 "ESO DET NDIT");
667 const double g = gain_lin->gain.data;
668 const double sigma_read = cpl_propertylist_get_double(
669 mdark->plist,
670 "ESO QC READ NOISE");
671
672 /* The Vacca formula for the variance works with intensity
673 measured in DN /sec. */
674
675 cpl_image_divide_scalar(linear_data, dit);
676
677 /* Calculate the variance as a special case of Vacca CDS treatment.
678 With nr = 1, equation 44 simplifies to:
679
680 VI = I + 2 * sigma_read^2
681 ------------ ----------------
682 g * nc * DIT g^2 * nc * DIT^2
683
684 first part being photon noise, second readout noise.
685
686 The 2 in the numerator of the readout noise component derives
687 from the 2 readouts in CDS ('pedestal' and 'signal') where
688 FAST_UNCORR only has 'signal'. Consequently we replace 2 by 1.
689
690 There presumably is some error associated with the reset at
691 the start of each integration but I don't know how to
692 characterise that.*/
693
694 /* Calculate the variance in stages */
695
696 /* gain is in electrons/ADU.
697 read-noise is in electrons. */
698
699 /* the photon noise component, can't be negative */
700
701 cpl_image_copy(variance, linear_data, 1, 1);
702 cpl_image_threshold(variance, 0.0, 1e32, 0.0, 1e32);
703 cpl_image_multiply_scalar(variance, 1.0 / (g * ndit * dit));
704
705 /* add the read noise component of Vacca eqn 56 */
706
707 cpl_image_add_scalar(variance,
708 sigma_read * sigma_read /
709 (g * g * ndit * dit * dit));
710
711 cpl_image_power(variance, 0.5);
712 if (probing) {
713 int ignore = 0;
714 double val = cpl_image_get(variance, x_probe, y_probe,
715 &ignore);
716 cpl_msg_info(cpl_func, "..eris_nix_detector probe %d %d "
717 "variance %5.3e", (int)x_probe, (int)y_probe, val);
718 cpl_msg_info(cpl_func, "..probe information sigma=%5.3e "
719 "g=%5.3e ndit=%d dit=%5.3e", sigma_read, g,
720 (int)ndit, dit);
721 }
722
723 /* ensure data and error masks are compatible to avoid potential
724 warning message from hdrl_create_image */
725
726 cpl_image_reject_from_mask(linear_data, cpl_image_get_bpm(variance));
727
728 } else {
729 cpl_msg_warning(cpl_func, "linearization not done - unsupported "
730 "detector mode: %s", det_mode);
731 }
732
733 /* tidy up */
734cleanup:
735
736 return self;
737}
738
739
740/*----------------------------------------------------------------------------*/
763/*----------------------------------------------------------------------------*/
764
765cpl_error_code end_linearize_and_variance(const gain_linearity * gain_lin,
766 const master_dark * mdark,
767 located_imagelist * limlist,
768 const cpl_size x_probe,
769 const cpl_size y_probe) {
770
771 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
772
773 cpl_msg_info(cpl_func, "%p %p %p", (const void*)gain_lin,
774 (const void*)mdark, (const void*)limlist);
775 cpl_ensure_code(gain_lin, CPL_ERROR_NULL_INPUT);
776 cpl_ensure_code(mdark, CPL_ERROR_NULL_INPUT);
777 cpl_ensure_code(limlist, CPL_ERROR_NULL_INPUT);
778 cpl_msg_info(cpl_func, "after %p %p %p", (const void*)gain_lin,
779 (const void*)mdark, (const void*)limlist);
780
781 if (limlist->size <= 0) return CPL_ERROR_NONE;
782
783 /* The non-linearity correction depends on f, a measure of the time in
784 in the read-out sequence that each pixel is read.
785
786 I think the result depends weakly on f, so set it to 1.0 for all
787 pixels, implying all pixels are read instantly on start of the
788 readout sequence */
789
790 cpl_size nx = hdrl_image_get_size_x(limlist->limages[0]->himage);
791 cpl_size ny = hdrl_image_get_size_y(limlist->limages[0]->himage);
792 cpl_image * f = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
793 cpl_image_fill_window(f, 1, 1, nx, ny, 1.0);
794
795 int probing = CPL_FALSE;
796 if (x_probe >= 1 && x_probe <= nx && y_probe >=1 && y_probe <= ny) {
797 probing = CPL_TRUE;
798 }
799
800 /* Loop through images */
801
802 for (cpl_size i = 0; i < limlist->size; i++) {
803
804 cpl_msg_info(cpl_func, "image %d", (int) i);
805
806 const char * det_mode = cpl_propertylist_get_string(
807 (limlist->limages[i])->plist,
808 "ESO DET READ CURNAME");
809 const int rot = cpl_propertylist_get_int(
810 (limlist->limages[i])->plist,
811 "ESO DET SEQ1 WIN ROT");
812 const cpl_size strx = cpl_propertylist_get_int(
813 (limlist->limages[i])->plist,
814 "ESO DET SEQ1 WIN STRX");
815 const cpl_size stry = cpl_propertylist_get_int(
816 (limlist->limages[i])->plist,
817 "ESO DET SEQ1 WIN STRY");
818 enu_check_error_code("failed to read detector mode information");
819 cpl_msg_info(cpl_func, "curname=%s rot=%d strx=%d stry=%d nx=%d ny=%d",
820 det_mode, (int)rot, (int)strx, (int)stry, (int)nx, (int)ny );
821
822 if (!strcmp(det_mode, "SLOW_LR_CDS")) {
823
824 /* CDS. Correlated Double Sampling.
825 In this mode the intensity is calculated from the difference
826 between 2 measurements at the start and end of the
827 integration. */
828
829 /* get the detector parameters required. */
830
831 double dit = enu_get_dit(limlist->limages[i]->plist);
832 const int ndit = cpl_propertylist_get_int(
833 (limlist->limages[i])->plist, "ESO DET NDIT");
834 const int nr = cpl_propertylist_get_int(
835 (limlist->limages[i])->plist, "ESO DET NDSAMPLES");
836 const double g = gain_lin->gain.data;
837 const double sigma_read = cpl_propertylist_get_double(
838 mdark->plist, "ESO QC READ NOISE");
839
840 cpl_image * data = cpl_image_duplicate(hdrl_image_get_image(
841 (limlist->limages[i])->himage));
842
843 /* The Vacca formula works with intensity measured in DN /sec. */
844
845 cpl_image_divide_scalar(data, dit);
846
847 /* correct for non-linearity first */
848
849 int ignore = 0;
850 if (probing) {
851 double probe_v = cpl_image_get(data, x_probe, y_probe,
852 &ignore);
853 cpl_msg_info(cpl_func, "data %4.2e %d", probe_v, ignore);
854 }
855
856 cpl_image * linear_data = end_vacca_linearize_cds(data,
857 gain_lin, dit, nr, f,
858 rot, strx, stry, x_probe, y_probe);
859
860 if (probing) {
861 double probe_v = cpl_image_get(linear_data, x_probe, y_probe,
862 &ignore);
863 cpl_msg_info(cpl_func, "linear_data %4.2e %d", probe_v,
864 ignore);
865 }
866
867 /* Calculate the variance in stages */
868
869 /* gain is in electrons/ADU.
870 read-noise is in electrons. */
871
872 /* the photon noise component of Vacca eqn 44 */
873
874 cpl_image * variance = cpl_image_duplicate(linear_data);
875
876 /* dt is the time taken to read the entire array - need to find
877 out this number */
878
879 /* actually, first set -ve numbers to zero as these make no
880 sense in terms of photon noise */
881
882 cpl_image_threshold(variance, 0.0, DBL_MAX, 0.0, DBL_MAX);
883 const double dt = 0.05;
884 cpl_image_multiply_scalar(variance,
885 (1.0 - dt * (nr * nr - 1) /
886 (3.0 * dit * nr)) /
887 (g * ndit * dit));
888 if (probing) {
889 cpl_msg_info(cpl_func, "photnoise factor %5.3e %d %5.3e %5.3e "
890 "%d %5.3e", dt, nr, dit, g, ndit,
891 (1.0 - dt * (nr * nr - 1) / (3.0 * dit * nr)) /
892 (g * ndit * dit));
893 }
894
895 /* add the read noise component of Vacca eqn 44 */
896
897 if (probing) {
898 cpl_msg_info(cpl_func, "readnoise comp %5.3e %5.3e %d %d"
899 "%5.3e% 5.3e", sigma_read, g, nr, ndit, dit,
900 2.0 * sigma_read * sigma_read /
901 (g * g * nr * ndit * dit * dit));
902 }
903 cpl_image_add_scalar(variance,
904 2.0 * sigma_read * sigma_read /
905 (g * g * nr * ndit * dit * dit));
906
907 /* make sure bad pixels are 0 */
908
909 cpl_image_fill_rejected(variance, 0.0);
910
911 /* construct the hdrl_image and replace the limlist entry */
912
913 cpl_image_power(variance, 0.5);
914 hdrl_image_delete((limlist->limages[i])->himage);
915 (limlist->limages[i])->himage = hdrl_image_create(linear_data,
916 variance);
917 /* tidy up */
918
919 cpl_image_delete(data);
920 cpl_image_delete(linear_data);
921 cpl_image_delete(variance);
922
923 } else if (!strcmp(det_mode, "SLOW_UP_THE_RAMP") ||
924 !strcmp(det_mode, "SLOW_GR_UTR")) {
925
926 cpl_msg_info(cpl_func, "slow gr utr %s", cpl_error_get_message());
927
928 /* Vacca et al. call this the 'Continuous Sampling Technique'.
929 In this mode the intensity is calculated by fitting a line
930 to a sequence of non-destructive reads carried out through
931 the DIT. */
932
933 /* get the detector parameters required */
934
935 double dit = enu_get_dit(limlist->limages[i]->plist);
936 const int ndit = cpl_propertylist_get_int(
937 (limlist->limages[i])->plist, "ESO DET NDIT");
938 const int nr = cpl_propertylist_get_int(
939 (limlist->limages[i])->plist, "ESO DET NDSAMPLES");
940 const double g = gain_lin->gain.data;
941 const double sigma_read = cpl_propertylist_get_double(
942 mdark->plist, "ESO QC READ NOISE");
943
944 /* The Vacca formula works with intensity measured in DN /sec. */
945
946 cpl_image * data = cpl_image_duplicate(hdrl_image_get_image(
947 (limlist->limages[i])->himage));
948 cpl_image_divide_scalar(data, dit);
949
950 /* correct for non-linearity first. This requires reconstruction
951 of the ramp samples from:
952
953 si = I * (i-f) * dt where I is DN/s
954 i is number of read
955 f is fractional pos. of det. in read
956 dt is duration of read cycle
957 */
958
959 cpl_image * linear_data = end_vacca_linearize_ramp(data,
960 gain_lin, dit, nr, f,
961 rot, strx, stry, x_probe, y_probe);
962
963 /* Calculate the variance in stages */
964
965 /* gain is in electrons/ADU.
966 read-noise is in electrons. */
967
968 /* the photon noise component of Vacca eqn 56 */
969
970 cpl_image * variance = cpl_image_duplicate(linear_data);
971 cpl_image_multiply_scalar(variance, 1.2 * (nr*nr + 1) /
972 ((nr + 1) * nr * g * dit));
973
974 /* add the read noise component of Vacca eqn 56 */
975
976 cpl_image_add_scalar(variance,
977 12.0 * sigma_read * sigma_read *
978 (nr - 1) /
979 ((nr + 1) * nr * g * g * dit * dit));
980
981 /* Eqn 56 does not account for the NDIT repeats, so divide
982 the variance by NDIT now */
983
984 cpl_image_divide_scalar(variance, (double) ndit);
985
986 /* construct the hdrl_image and replace the limlist entry */
987
988 cpl_image_power(variance, 0.5);
989
990 /* ensure data and error masks are compatible to avoid potential
991 warning message from hdrl_create_image */
992
993 cpl_mask * vbpm = cpl_mask_duplicate(cpl_image_get_bpm(variance));
994 cpl_mask * ignore = cpl_image_set_bpm(linear_data, vbpm);
995 cpl_mask_delete(ignore); ignore = NULL;
996
997 hdrl_image_delete((limlist->limages[i])->himage);
998 (limlist->limages[i])->himage = hdrl_image_create(linear_data,
999 variance);
1000 /* tidy up */
1001
1002 cpl_image_delete(data);
1003 cpl_image_delete(linear_data);
1004 cpl_image_delete(variance);
1005
1006 } else {
1007 cpl_msg_warning(cpl_func, "linearization not done - unsupported "
1008 "detector mode: %s", det_mode);
1009 }
1010 }
1011
1012
1013cleanup:
1014
1015 cpl_image_delete(f);
1016
1017 return cpl_error_get_code();
1018}
1019
1020
1021/*----------------------------------------------------------------------------*/
1050/*----------------------------------------------------------------------------*/
1051
1052cpl_image * end_vacca_linearize_cds(cpl_image * intensity,
1053 const gain_linearity * gain_lin,
1054 const double dit,
1055 const cpl_size nr,
1056 const cpl_image * f,
1057 cpl_size rot,
1058 cpl_size strx,
1059 cpl_size stry,
1060 cpl_size x_probe,
1061 cpl_size y_probe) {
1062
1063 if (cpl_error_get_code() != CPL_ERROR_NONE) return NULL;
1064
1065 cpl_ensure(intensity, CPL_ERROR_NULL_INPUT, NULL);
1066 cpl_ensure(gain_lin, CPL_ERROR_NULL_INPUT, NULL);
1067 cpl_ensure(nr > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1068
1069 cpl_image * change = NULL;
1070 cpl_image * result = NULL;
1071
1072 cpl_size nx = cpl_image_get_size_x(intensity);
1073 cpl_size ny = cpl_image_get_size_y(intensity);
1074
1075 int probing = CPL_FALSE;
1076 if (x_probe >= 1 && x_probe <= nx && y_probe >=1 && y_probe <= ny) {
1077 probing = CPL_TRUE;
1078 }
1079
1080 /* now do the iterative linearization */
1081
1082 cpl_image ** iteration = cpl_calloc(LINEARIZE_MAXITER,
1083 sizeof(cpl_image *));
1084 cpl_size niter = 0;
1085 iteration[0] = cpl_image_duplicate(intensity);
1086
1087 /* dt is the time taken to read the entire array - need to find
1088 out this number! */
1089
1090 const double dt = 0.05;
1091
1092 while (niter+1 < LINEARIZE_MAXITER &&
1093 cpl_error_get_code() == CPL_ERROR_NONE) {
1094
1095 /* estimate the pedestal values following Vacca eqn 23. For NIX
1096 the equations look different as intensity = Stot / nr * nc * dit */
1097
1098 cpl_image * pedestal = cpl_image_multiply_scalar_create(f, -1.0);
1099 cpl_image_add_scalar(pedestal, (double) (nr + 1) / 2);
1100 cpl_image_multiply(pedestal, iteration[niter]);
1101 cpl_image_multiply_scalar(pedestal, dt);
1102 cpl_image * signal = cpl_image_multiply_scalar_create(iteration[0],
1103 dit);
1104 cpl_image_add(signal, pedestal);
1105
1106 if (probing) {
1107 int ignore = 0;
1108 double probe_val = cpl_image_get(iteration[niter], x_probe,
1109 y_probe, &ignore);
1110 if (!ignore) {
1111 double probe_p = cpl_image_get(pedestal, x_probe, y_probe,
1112 &ignore);
1113 double probe_s = cpl_image_get(signal, x_probe, y_probe,
1114 &ignore);
1115 cpl_msg_info(cpl_func, "linearizing: (pix %d,%d) niter=%d "
1116 "I=%4.2e pedestal=%4.2e signal=%4.2e",
1117 (int)x_probe, (int)y_probe, (int)niter,
1118 probe_val, probe_p, probe_s);
1119 } else {
1120 cpl_msg_info(cpl_func, "linearizing: (pix %d,%d) niter=%d "
1121 "bad pixel", (int)x_probe, (int)y_probe,
1122 (int)niter);
1123 }
1124 }
1125
1126 /* linearize the samples in the current estimate */
1127
1128 end_linearize_image(pedestal, gain_lin, rot, strx, stry,
1129 x_probe, y_probe);
1130 end_linearize_image(signal, gain_lin, rot, strx, stry,
1131 x_probe, y_probe);
1132
1133 /* calculate new value for intensity */
1134
1135 niter++;
1136 iteration[niter] = cpl_image_subtract_create(signal, pedestal);
1137 cpl_image_divide_scalar(iteration[niter], dit);
1138 cpl_image_delete(pedestal);
1139 cpl_image_delete(signal);
1140 }
1141
1142 result = cpl_image_duplicate(iteration[niter]);
1143 if (niter > 0) {
1144
1145 /* Set the image mask bad where the linearization did not
1146 converge; more than 1 per cent change in last iteration */
1147
1148 change = cpl_image_divide_create(iteration[niter],
1149 iteration[niter-1]);
1150 cpl_mask_threshold_image(cpl_image_get_bpm(result), change, 0.99,
1151 1.01, CPL_BINARY_0);
1152
1153 /* Set bad pixels to 0 */
1154
1155 cpl_image_fill_rejected(result, 0.0);
1156 }
1157
1158 /* tidy up memory */
1159
1160 for (cpl_size i = 0; i < LINEARIZE_MAXITER; i++) {
1161 cpl_image_delete(iteration[i]);
1162 }
1163 cpl_free(iteration);
1164 cpl_image_delete(change);
1165
1166 /* return NULL on error */
1167
1168 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1169 cpl_image_delete(result);
1170 result = NULL;
1171 }
1172
1173 return result;
1174}
1175
1176
1177/*----------------------------------------------------------------------------*/
1205/*----------------------------------------------------------------------------*/
1206
1207cpl_image * end_vacca_linearize_ramp(cpl_image * intensity,
1208 const gain_linearity * gain_lin,
1209 const double dit,
1210 const cpl_size nr,
1211 const cpl_image * f,
1212 const cpl_size rot,
1213 const cpl_size strx,
1214 const cpl_size stry,
1215 const cpl_size x_probe,
1216 const cpl_size y_probe) {
1217
1218 if (cpl_error_get_code() != CPL_ERROR_NONE) return NULL;
1219
1220#ifdef _OPENMP
1221 double time1, time2, time3, time4, time11, time12, time13, time14;
1222 time1 = omp_get_wtime();
1223#else
1224 clock_t time1, time2, time3, time4, time11, time12, time13, time14;
1225 time1 = clock();
1226#endif
1227
1228 cpl_ensure(intensity, CPL_ERROR_NULL_INPUT, NULL);
1229 cpl_ensure(gain_lin, CPL_ERROR_NULL_INPUT, NULL);
1230 cpl_ensure(nr > 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
1231
1232 cpl_image * result = NULL;
1233 cpl_image * change = NULL;
1234
1235 cpl_size nx = cpl_image_get_size_x(intensity);
1236 cpl_size ny = cpl_image_get_size_y(intensity);
1237 int probing = CPL_FALSE;
1238 cpl_msg_info(cpl_func, "%d %d %d %d", (int)x_probe, (int)y_probe, (int)nx, (int)ny);
1239 if (x_probe >= 1 && x_probe <= nx && y_probe >=1 && y_probe <= ny) {
1240 probing = CPL_TRUE;
1241 cpl_msg_info(cpl_func, "messaging on");
1242 }
1243 double s = 0.0;
1244 int reject = 0;
1245
1246 /* now do the iterative linearization */
1247
1248 cpl_image ** iteration = cpl_calloc(LINEARIZE_MAXITER,
1249 sizeof(cpl_image *));
1250 cpl_size niter = 0;
1251 iteration[0] = cpl_image_duplicate(intensity);
1252 if (probing) {
1253 s = cpl_image_get(intensity, x_probe, y_probe, &reject);
1254 cpl_msg_info(cpl_func, "initial %s %5.2f", cpl_error_get_message(), s);
1255 }
1256
1257#ifdef _OPENMP
1258 time2 = omp_get_wtime();
1259#else
1260 time2 = clock();
1261#endif
1262
1263 while (niter+1 < LINEARIZE_MAXITER &&
1264 cpl_error_get_code() == CPL_ERROR_NONE) {
1265
1266 /* estimate the sample values following Vacca eqn 49 */
1267
1268#ifdef _OPENMP
1269 time11 = omp_get_wtime();
1270#else
1271 time11 = clock();
1272#endif
1273 eris_nix_samples * samples = end_calculate_samples(iteration[niter],
1274 iteration[0],
1275 nr, dit, f);
1276
1277 if (probing) {
1278 cpl_msg_info(cpl_func, "samples before linearization: is, reject, s");
1279 for (cpl_size is=0; is<samples->nr; is++) {
1280 s = cpl_image_get(samples->samples[is], x_probe, y_probe, &reject);
1281 cpl_msg_info(cpl_func, "%d %d %5.2f", (int)is, reject, s);
1282 }
1283 }
1284
1285 /* linearize the samples in the current estimate */
1286
1287#ifdef _OPENMP
1288 time12 = omp_get_wtime();
1289#else
1290 time12 = clock();
1291#endif
1292 for (cpl_size i = 0; i < nr; i++) {
1293 end_linearize_image(samples->samples[i], gain_lin, rot,
1294 strx, stry, x_probe, y_probe);
1295 }
1296
1297 if (probing) {
1298 cpl_msg_info(cpl_func, "samples after: is, reject, s");
1299 for (cpl_size is=0; is<samples->nr; is++) {
1300 s = cpl_image_get(samples->samples[is], x_probe, y_probe, &reject);
1301 cpl_msg_info(cpl_func, "%d %d %5.2f", (int)is, reject, s);
1302 }
1303 }
1304
1305 /* calculate new value for intensity */
1306
1307#ifdef _OPENMP
1308 time13 = omp_get_wtime();
1309#else
1310 time13 = clock();
1311#endif
1312 niter++;
1313 iteration[niter] = end_uptheramp_reduce(samples, dit);
1314
1315 if (probing) {
1316 s = cpl_image_get(iteration[niter], x_probe, y_probe, &reject);
1317 cpl_msg_info(cpl_func, "iteration %s %d %9.4e", cpl_error_get_message(),
1318 (int)niter, s);
1319
1320 }
1321
1322#ifdef _OPENMP
1323 time14 = omp_get_wtime();
1324 cpl_msg_info(cpl_func, "%d ramp samp %5.2e lin %5.2e calc %5.2e",
1325 (int)niter,
1326 time12-time11,
1327 time13-time12,
1328 time14-time13);
1329#else
1330 time14 = clock();
1331 cpl_msg_info(cpl_func, "%d ramp samp %5.2e lin %5.2e calc %5.2e",
1332 (int)niter,
1333 (double)(time12-time11) / CLOCKS_PER_SEC,
1334 (double)(time13-time12) / CLOCKS_PER_SEC,
1335 (double)(time14-time13) / CLOCKS_PER_SEC);
1336#endif
1337 end_samples_delete(samples);
1338 }
1339
1340#ifdef _OPENMP
1341 time3 = omp_get_wtime();
1342#else
1343 time3 = clock();
1344#endif
1345
1346 result = cpl_image_duplicate(iteration[niter]);
1347
1348 if (probing) {
1349 s = cpl_image_get(result, x_probe, y_probe, &reject);
1350 cpl_msg_info(cpl_func, "result %s %5.2f", cpl_error_get_message(), s);
1351 }
1352
1353 if (niter > 0) {
1354
1355 /* Set the image mask bad where the linearization did not
1356 converge; more than 1 per cent change in last iteration */
1357
1358 change = cpl_image_divide_create(iteration[niter],
1359 iteration[niter-1]);
1360 cpl_mask_threshold_image(cpl_image_get_bpm(result), change, 0.99,
1361 1.01, CPL_BINARY_0);
1362 }
1363
1364 /* tidy up memory */
1365
1366 for (cpl_size i = 0; i < LINEARIZE_MAXITER; i++) {
1367 cpl_image_delete(iteration[i]);
1368 }
1369 cpl_free(iteration);
1370 cpl_image_delete(change);
1371
1372 /* return NULL on error */
1373
1374 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1375 cpl_image_delete(result);
1376 result = NULL;
1377 }
1378
1379#ifdef _OPENMP
1380 time4 = omp_get_wtime();
1381 cpl_msg_info(cpl_func, "ramp setup %5.2e lin %5.2e tidy %5.2e",
1382 time2-time1,
1383 time3-time2,
1384 time4-time3);
1385#else
1386 time4 = clock();
1387 cpl_msg_info(cpl_func, "ramp setup %5.2e lin %5.2e tidy %5.2e",
1388 (double)(time2-time1) / CLOCKS_PER_SEC,
1389 (double)(time3-time2) / CLOCKS_PER_SEC,
1390 (double)(time4-time3) / CLOCKS_PER_SEC);
1391#endif
1392
1393 return result;
1394}
1395
1396/*----------------------------------------------------------------------------*/
1412/*----------------------------------------------------------------------------*/
1413
1414double engl_lin_correct(const double obs,
1415 const cpl_size fit_order,
1416 const double* coeffs,
1417 const cpl_binary fit_quality,
1418 const double saturation,
1419 cpl_binary * rejected,
1420 cpl_binary * saturated,
1421 const int debug) {
1422
1423 double result = obs;
1424 if (cpl_error_get_code()) return 0.0;
1425 if (debug)
1426 cpl_msg_info(cpl_func, "Saturation ptr: %p", (const void*)saturated);
1427
1428 engl_lin_correct_(&result,
1429 fit_order,
1430 coeffs,
1431 fit_quality,
1432 saturation,
1433 rejected,
1434 debug);
1435 return result;
1436
1437}
1438
1439/*----------------------------------------------------------------------------*/
1455/*----------------------------------------------------------------------------*/
1456inline static
1457void engl_lin_correct_(double * pobs,
1458 const cpl_size fit_order,
1459 const double* coeffs,
1460 const cpl_binary fit_quality,
1461 const double saturation,
1462 cpl_binary * rejected,
1463 const int debug) {
1464
1465 if (fit_quality == CPL_BINARY_1) {
1466
1467 if (debug) cpl_msg_info(cpl_func, "....debug bad quality");
1468 *rejected = CPL_BINARY_1;
1469
1470 } else if (coeffs[1] <= 0.0) {
1471
1472 /* Negative sloping curve makes no sense */
1473
1474 if (debug) cpl_msg_info(cpl_func, "....debug bad slope");
1475 *rejected = CPL_BINARY_1;
1476
1477 } else if (*pobs > 0.0) {
1478
1479 /* find the t value for where the obs value sits on the linearisation
1480 curve. Points outside curve range are set bad */
1481
1482 /* In saturation correct the pixel as it it was _at_ saturation. The
1483 aim of this is to avoid introducing discontinuities to the image */
1484
1485 const double useobs = *pobs > saturation ? saturation : *pobs;
1486 double curve = 0.0;
1487 /* On failure t is zero */
1488 const double t = engl_lin_find_(*pobs, 0.9 * useobs / coeffs[1],
1489 1.5 * useobs / coeffs[1],
1490 fit_order, coeffs, &curve);
1491 /* Calculate the correction and apply it (zero on failure) */
1492 const double correction = (coeffs[1] * t) / curve;
1493
1494 *pobs *= correction;
1495 *rejected = t > 0.0 ? CPL_BINARY_0 : CPL_BINARY_1;
1496
1497 if (debug) {
1498 if (useobs == saturation)
1499 cpl_msg_info(cpl_func, "....debug saturated");
1500
1501 for (int j = fit_order-1; j>-1; j--) {
1502 cpl_msg_info(cpl_func, "....debug curve coeffs %d %5.3e",
1503 j, coeffs[j]);
1504 }
1505 cpl_msg_info(cpl_func, "....debug t %4.2f", t);
1506 cpl_msg_info(cpl_func, "....debug correction %6.4e %4.2e "
1507 "%4.2e", correction, *pobs, curve);
1508 }
1509
1510 } else if (debug) {
1511
1512 /* Negative values are off the linearization curve, do nothing */
1513
1514 cpl_msg_info(cpl_func, "....debug negative");
1515 }
1516}
1517
1518/*----------------------------------------------------------------------------*/
1531/*----------------------------------------------------------------------------*/
1532
1533double engl_lin_find(const double obs,
1534 double low_t,
1535 double high_t,
1536 const cpl_size fit_order,
1537 const double* coeffs) {
1538
1539 double dummy = 0.0;
1540 return cpl_error_get_code() ? -1.0 :
1541 engl_lin_find_(obs, low_t, high_t, fit_order, coeffs, &dummy);
1542}
1543
1544/*----------------------------------------------------------------------------*/
1560/*----------------------------------------------------------------------------*/
1561
1562inline static
1563double engl_lin_find_(const double obs,
1564 double low_t,
1565 double high_t,
1566 const cpl_size fit_order,
1567 const double* coeffs,
1568 double * pcurve) {
1569
1570 double result = 0.0;
1571
1572 cpl_size iter = 0;
1573 double low_curve = 0.0;
1574 double high_curve = 0.0;
1575
1576 *pcurve = 0.0;
1577 do {
1578
1579 /* calculate values of curve as required at low_t, high_t and
1580 mid_t */
1581
1582 if (low_curve == 0.0) {
1583 int j = fit_order-2; /* Peel off iterations below 4 */
1584 low_curve = coeffs[fit_order-1];
1585 for (; j >= 3; j--) {
1586 low_curve = low_curve * low_t + coeffs[j];
1587 }
1588 switch (j) {
1589 case 2:
1590 low_curve = low_curve * low_t + coeffs[2];
1591 CPL_ATTR_FALLTRHU; /* fall through */
1592 case 1:
1593 low_curve = low_curve * low_t + coeffs[1];
1594 CPL_ATTR_FALLTRHU; /* fall through */
1595 case 0:
1596 low_curve *= low_t; /* Constant term is zero */
1597 }
1598 }
1599 if (high_curve == 0.0) {
1600 int j = fit_order-2; /* Peel off iterations below 4 */
1601 high_curve = coeffs[fit_order-1];
1602 for (; j >= 3; j--) {
1603 high_curve = high_curve * high_t + coeffs[j];
1604 }
1605 switch (j) {
1606 case 2:
1607 high_curve = high_curve * high_t + coeffs[2];
1608 CPL_ATTR_FALLTRHU; /* fall through */
1609 case 1:
1610 high_curve = high_curve * high_t + coeffs[1];
1611 CPL_ATTR_FALLTRHU; /* fall through */
1612 case 0:
1613 high_curve *= high_t; /* Constant term is zero */
1614 }
1615 }
1616 double mid_t = (low_t + high_t) / 2.0;
1617 double mid_curve = coeffs[fit_order-1];
1618 int j = fit_order-2; /* Peel off iterations below 4 */
1619 for (; j >= 3; j--) {
1620 mid_curve = mid_curve * mid_t + coeffs[j];
1621 }
1622 switch (j) {
1623 case 2:
1624 mid_curve = mid_curve * mid_t + coeffs[2];
1625 CPL_ATTR_FALLTRHU; /* fall through */
1626 case 1:
1627 mid_curve = mid_curve * mid_t + coeffs[1];
1628 CPL_ATTR_FALLTRHU; /* fall through */
1629 case 0:
1630 mid_curve *= mid_t; /* Constant term is zero */
1631 }
1632
1633 /* decide what to do based on position of obs */
1634
1635 if (fabs(obs - mid_curve) < MAX_LIN_DIFFERENCE) {
1636 *pcurve = mid_curve;
1637 result = mid_t;
1638 break;
1639 } else if ((obs > low_curve) && (obs < mid_curve)) {
1640 high_t = mid_t;
1641 high_curve = 0.0;
1642 } else if ((obs > mid_curve) && (obs < high_curve)) {
1643 low_t = mid_t;
1644 low_curve = 0.0;
1645 } else {
1646
1647 /* point is outside range of curve */
1648
1649 break;
1650 }
1651
1652 } while (iter++ < MAX_LIN_DEPTH);
1653
1654 /* trap failure to reach result inside max number of iterations */
1655
1656 if (iter >= MAX_LIN_DEPTH) {
1657 cpl_msg_info(cpl_func, "max depth %4.2e %4.2e %4.2e %d %4.2e %4.2e "
1658 "%4.2e", obs, low_t, high_t,
1659 (int)fit_order, coeffs[0], coeffs[1],coeffs[3]);
1660 }
1661
1662 return result;
1663}
1664
1665
cpl_error_code enu_get_window_info(cpl_size *nx, cpl_size *ny, int *rot, cpl_size *strx, cpl_size *stry, cpl_size *nx_chip, cpl_size *ny_chip, cpl_boolean *windowed, const cpl_propertylist *plist)
Get the detector 'window' information.
const char * enu_get_det_mode(const cpl_propertylist *plist)
Get the detector mode of an integration.
double enu_get_dit(const cpl_propertylist *plist)
Get the DIT of an integration.
hdrl_image * hdrl_image_duplicate(const hdrl_image *himg)
copy hdrl_image
Definition: hdrl_image.c:391
cpl_image * hdrl_image_get_error(hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:131
cpl_size hdrl_image_get_size_y(const hdrl_image *self)
return size of Y dimension of image
Definition: hdrl_image.c:540
cpl_size hdrl_image_get_size_x(const hdrl_image *self)
return size of X dimension of image
Definition: hdrl_image.c:525
hdrl_image * hdrl_image_create(const cpl_image *image, const cpl_image *error)
create a new hdrl_image from to existing images by copying them
Definition: hdrl_image.c:295
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
void hdrl_image_delete(hdrl_image *himg)
delete hdrl_image
Definition: hdrl_image.c:379