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