36 #include "irplib_strehl.h"
37 #include "irplib_utils.h"
53 #ifndef IRPLIB_STREHL_RAD_CENTRAL
54 #define IRPLIB_STREHL_RAD_CENTRAL 5
57 #ifndef IRPLIB_STREHL_DETECT_LEVEL
58 #define IRPLIB_STREHL_DETECT_LEVEL 5.0
61 #define IRPLIB_DISK_BG_MIN_PIX_NB 30
62 #define IRPLIB_DISK_BG_REJ_LOW 0.1
63 #define IRPLIB_DISK_BG_REJ_HIGH 0.1
66 #define IRPLIB_MIN CPL_MIN
68 #define IRPLIB_MIN(A,B) ((A) < (B) ? (A) : (B))
72 #define IRPLIB_MAX CPL_MAX
74 #define IRPLIB_MAX(A,B) ((A) > (B) ? (A) : (B))
81 static cpl_image * irplib_strehl_generate_otf(
double,
double,
double,
double,
83 static double PSF_H1(
double,
double,
double);
84 static double PSF_H2(
double,
double);
85 static double PSF_G(
double,
double);
86 static double PSF_sinc_norm(
double);
87 static double PSF_TelOTF(
double,
double);
88 static cpl_error_code update_bad_pixel_map(cpl_image* im);
90 #ifndef IRPLIB_NO_FIT_GAUSSIAN
91 #ifdef IRPLIB_STREHL_USE_CPL_IMAGE_FIT_GAUSSIAN
92 static double irplib_gaussian_2d(
double,
double,
double,
double,
double);
95 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(6, 9, 1)
96 #define irplib_gaussian_eval_2d cpl_gaussian_eval_2d
98 static double irplib_gaussian_eval_2d(
const cpl_array *,
double,
double);
101 static uint32_t irplib_roundup_power2(uint32_t v) CPL_ATTR_CONST;
104 cpl_error_code irplib_gaussian_maxpos(
const cpl_image *,
121 cpl_error_code update_bad_pixel_map(cpl_image* im)
123 int szx = cpl_image_get_size_x(im);
124 int szy = cpl_image_get_size_y(im);
126 cpl_mask* bpm = cpl_image_get_bpm(im);
128 for (x = 1; x <=szx; x++)
131 for(y = 1; y <= szy; y++)
134 double value = cpl_image_get(im, x, y, &isnull);
137 cpl_mask_set(bpm, x, y, CPL_BINARY_1);
141 return cpl_error_get_code();
173 cpl_error_code irplib_strehl_mark_bad_and_compute(cpl_image * im,
196 cpl_ensure_code(!update_bad_pixel_map(im), cpl_error_get_code());
197 return irplib_strehl_compute(im, m1, m2, lam, dlam, pscale, size, xpos, ypos,
245 cpl_error_code irplib_strehl_compute(
const cpl_image * im,
269 double star_radius, max_radius;
272 const double window_size = (double)(IRPLIB_STREHL_RAD_CENTRAL);
275 const double strehl_error_coefficient = CPL_MATH_PI * 0.007 / 0.0271;
279 #ifndef IRPLIB_NO_FIT_GAUSSIAN
280 double xposfit, yposfit, peak;
283 cpl_errorstate prestate = cpl_errorstate_get();
286 cpl_ensure_code(window_size > 0.0, CPL_ERROR_ILLEGAL_INPUT);
289 cpl_ensure_code(im != NULL, CPL_ERROR_NULL_INPUT);
290 cpl_ensure_code(strehl != NULL, CPL_ERROR_NULL_INPUT);
291 cpl_ensure_code(strehl_err != NULL, CPL_ERROR_NULL_INPUT);
292 cpl_ensure_code(star_bg != NULL, CPL_ERROR_NULL_INPUT);
293 cpl_ensure_code(star_peak != NULL, CPL_ERROR_NULL_INPUT);
294 cpl_ensure_code(star_flux != NULL, CPL_ERROR_NULL_INPUT);
295 cpl_ensure_code(psf_peak != NULL, CPL_ERROR_NULL_INPUT);
296 cpl_ensure_code(psf_flux != NULL, CPL_ERROR_NULL_INPUT);
298 cpl_ensure_code(pscale > 0.0, CPL_ERROR_ILLEGAL_INPUT);
300 cpl_ensure_code(r1 > 0.0, CPL_ERROR_ILLEGAL_INPUT);
301 cpl_ensure_code(r2 > 0.0, CPL_ERROR_ILLEGAL_INPUT);
302 cpl_ensure_code(r3 > r2, CPL_ERROR_ILLEGAL_INPUT);
308 psf = irplib_strehl_generate_psf(m1, m2, lam, dlam, pscale, size);
310 return cpl_error_set_where(cpl_func);
314 *psf_peak = cpl_image_get_max(psf);
315 cpl_image_delete(psf);
317 assert( *psf_peak > 0.0);
320 #ifndef IRPLIB_NO_FIT_GAUSSIAN
321 code = irplib_gaussian_maxpos(im, IRPLIB_STREHL_DETECT_LEVEL,
322 &xposfit, &yposfit, &peak);
324 cpl_errorstate_set(prestate);
332 *star_bg = irplib_strehl_ring_background(im, xpos, ypos,
333 r2/pscale, r3/pscale,
334 IRPLIB_BG_METHOD_AVER_REJ);
335 if (!cpl_errorstate_is_equal(prestate)) {
336 return cpl_error_set_where(cpl_func);
340 star_radius = r1/pscale;
343 *star_flux = irplib_strehl_disk_flux(im, xpos, ypos, star_radius, *star_bg);
345 if (*star_flux <= 0.0) {
346 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
347 "Non-positive star flux=%g (Star "
348 "background=%g)", *star_flux, *star_bg);
352 max_radius = window_size < star_radius ? window_size : star_radius;
353 cpl_ensure_code(!irplib_strehl_disk_max(im, xpos, ypos, max_radius,
354 star_peak), cpl_error_get_code());
355 *star_peak -= *star_bg;
357 if (*star_flux <= 0.0) {
358 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
359 "Non-positive star peak=%g (Star "
360 "background=%g, Star flux=%g)",
361 *star_flux, *star_bg, *star_flux);
366 *strehl = (*star_peak * *psf_flux ) / ( *star_flux * *psf_peak);
368 #ifndef IRPLIB_NO_FIT_GAUSSIAN
369 if (code == CPL_ERROR_NONE && peak > *star_peak && *star_peak > 0.0 &&
370 *strehl * peak / *star_peak <= 1.0) {
371 cpl_msg_debug(cpl_func,
"Increasing Strehl from %g: %g (%g)",
372 *strehl, *strehl * peak / *star_peak,
374 *strehl *= peak / *star_peak;
386 while (cpl_flux_get_noise_ring(im, ring, noise_box_sz, noise_nsamples,
387 bg_noise, NULL) && --ring_tries > 0);
388 if (ring_tries > 0) {
389 cpl_errorstate_set(prestate);
391 return cpl_error_set_where(cpl_func);
394 *strehl_err = strehl_error_coefficient * (*bg_noise) * pscale *
395 star_radius * star_radius / *star_flux;
398 cpl_msg_warning(cpl_func,
"Extreme Strehl-ratio=%g (strehl-error=%g, "
399 "star_peak=%g, star_flux=%g, psf_peak=%g, psf_flux=%g)",
400 *strehl, *strehl_err, *star_peak, *star_flux, *psf_peak,
405 return *strehl_err >= 0.0
407 : cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
408 "Negative strehl-error=%g (Strehl-ratio=%g, "
409 "star_peak=%g, star_flux=%g, psf_peak=%g, "
410 "psf_flux=%g", *strehl_err, *strehl,
411 *star_peak, *star_flux, *psf_peak, *psf_flux);
431 double irplib_strehl_disk_flux(
const cpl_image * im,
437 const int nx = cpl_image_get_size_x(im);
438 const int ny = cpl_image_get_size_y(im);
440 const int lx = (int)(xpos - rad);
441 const int ly = (int)(ypos - rad);
443 const int ux = (int)(xpos + rad) + 1;
444 const int uy = (int)(ypos + rad) + 1;
446 const double sqr = rad * rad;
452 cpl_ensure(im != NULL, CPL_ERROR_NULL_INPUT, 0.0);
453 cpl_ensure(rad > 0.0, CPL_ERROR_ILLEGAL_INPUT, 0.0);
455 for (j = IRPLIB_MAX(ly, 0); j < IRPLIB_MIN(uy, ny-1); j++) {
456 const double yj = (double)j - ypos;
457 for (i = IRPLIB_MAX(lx, 0); i < IRPLIB_MIN(ux, nx-1); i++) {
458 const double xi = (double)i - xpos;
459 const double dist = yj * yj + xi * xi;
462 const double value = cpl_image_get(im, i+1, j+1, &isbad);
464 if (!isbad && irplib_isnan(value) == 0) {
491 double irplib_strehl_ring_background(
const cpl_image * im,
496 irplib_strehl_bg_method mode)
498 const int nx = cpl_image_get_size_x(im);
499 const int ny = cpl_image_get_size_y(im);
501 const int lx = (int)(xpos - rad_ext);
502 const int ly = (int)(ypos - rad_ext);
504 const int ux = (int)(xpos + rad_ext) + 1;
505 const int uy = (int)(ypos + rad_ext) + 1;
507 const double sqr_int = rad_int * rad_int;
508 const double sqr_ext = rad_ext * rad_ext;
509 cpl_vector * pix_arr;
514 cpl_ensure(im != NULL, CPL_ERROR_NULL_INPUT, 0.0);
515 cpl_ensure(rad_int > 0.0, CPL_ERROR_ILLEGAL_INPUT, 0.0);
516 cpl_ensure(rad_ext > rad_int, CPL_ERROR_ILLEGAL_INPUT, 0.0);
518 cpl_ensure(mode == IRPLIB_BG_METHOD_AVER_REJ ||
519 mode == IRPLIB_BG_METHOD_MEDIAN,
520 CPL_ERROR_UNSUPPORTED_MODE, 0.0);
522 mpix = (int)((2.0 * rad_ext + 1.0) * (2.0 * rad_ext + 1.0));
525 pix_arr = cpl_vector_new(mpix);
530 for (j = IRPLIB_MAX(ly, 0); j < IRPLIB_MIN(uy, ny-1); j++) {
531 const double yj = (double)j - ypos;
532 for (i = IRPLIB_MAX(lx, 0); i < IRPLIB_MIN(ux, nx-1); i++) {
533 const double xi = (double)i - xpos;
534 const double dist = yj * yj + xi * xi;
535 if (sqr_int <= dist && dist <= sqr_ext) {
537 const double value = cpl_image_get(im, i+1, j+1, &isbad);
539 if (!isbad && irplib_isnan(value) == 0) {
540 cpl_vector_set(pix_arr, npix, value);
547 assert(npix <= mpix);
549 if (npix < IRPLIB_DISK_BG_MIN_PIX_NB) {
550 cpl_vector_delete(pix_arr);
551 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
"Need "
552 "at least %d (not %d <= %d) samples to "
553 "compute noise", IRPLIB_DISK_BG_MIN_PIX_NB,
561 pix_arr = cpl_vector_wrap(npix, (
double*)cpl_vector_unwrap(pix_arr));
563 if (mode == IRPLIB_BG_METHOD_AVER_REJ) {
564 const int low_ind = (int)((
double)npix * IRPLIB_DISK_BG_REJ_LOW);
565 const int high_ind = (int)((
double)npix
566 * (1.0 - IRPLIB_DISK_BG_REJ_HIGH));
569 cpl_vector_sort(pix_arr, CPL_SORT_ASCENDING);
571 for (i=low_ind; i<high_ind; i++) {
572 flux += cpl_vector_get(pix_arr, i);
574 if (high_ind - low_ind > 1) flux /= (double)(high_ind - low_ind);
576 flux = cpl_vector_get_median(pix_arr);
579 cpl_vector_delete(pix_arr);
605 cpl_image * irplib_strehl_generate_psf(
double m1,
612 cpl_image * otf_image = irplib_strehl_generate_otf(m1, m2, lam, dlam,
615 if (otf_image == NULL ||
626 cpl_image_fft(otf_image, NULL, CPL_FFT_UNNORMALIZED) ||
629 cpl_image_abs(otf_image) ||
632 cpl_image_normalise(otf_image, CPL_NORM_FLUX)) {
634 (void)cpl_error_set_where(cpl_func);
635 cpl_image_delete(otf_image);
661 static cpl_image * irplib_strehl_generate_otf(
double m1,
670 const double obs_ratio = m1 != 0.0 ? m2 / m1 : 0.0;
672 const double rpscale = pscale * CPL_MATH_2PI / (double)(360 * 60 * 60);
674 const double f_max = m1 * rpscale * (double)size;
677 const int pix0 = size / 2;
681 cpl_ensure(m2 > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
682 cpl_ensure(m1 > m2, CPL_ERROR_ILLEGAL_INPUT, NULL);
683 cpl_ensure(dlam > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
684 cpl_ensure(pscale > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
685 cpl_ensure(size > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
687 cpl_ensure(size % 2 == 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
690 cpl_ensure(2.0 * lam > dlam, CPL_ERROR_ILLEGAL_INPUT, NULL);
697 otf_data = (
double*)cpl_malloc(size * size *
sizeof(*otf_data));
704 for (j = 0; j <= pix0; j++) {
705 double sinc_y_9 = 0.0;
706 for (i = 0; i <= j; i++) {
707 if (i == 0 && j == 0) {
708 otf_data[size * pix0 + pix0] = 1.0;
710 const double x = (double)i;
711 const double y = (double)j;
712 const double sqdist = x * x + y * y;
713 double f_lambda, sinc_xy_9 = 0.0;
721 for (k = 4; k >= -4; k--) {
723 const double lambda = lam - dlam * (double)k / 8.0;
727 if (sqdist * lambda * lambda >= f_max * f_max)
break;
730 f_lambda = sqrt(sqdist) / f_max;
733 sinc_xy_9 = sinc_y_9 =
734 PSF_sinc_norm(y / (
double)size) / 9.0;
736 sinc_xy_9 = sinc_y_9 *
737 PSF_sinc_norm(x / (
double)size);
741 otfxy += PSF_TelOTF(f_lambda * lambda, obs_ratio);
747 otf_data[size * (pix0 - j) + pix0 - i] = otfxy;
748 otf_data[size * (pix0 - i) + pix0 - j] = otfxy;
750 otf_data[size * (pix0 - j) + pix0 + i] = otfxy;
751 otf_data[size * (pix0 + i) + pix0 - j] = otfxy;
753 otf_data[size * (pix0 + j) + pix0 - i] = otfxy;
754 otf_data[size * (pix0 - i) + pix0 + j] = otfxy;
755 otf_data[size * (pix0 + j) + pix0 + i] = otfxy;
756 otf_data[size * (pix0 + i) + pix0 + j] = otfxy;
763 return cpl_image_wrap_double(size, size, otf_data);
769 static double PSF_H1(
774 const double e = fabs(1.0-v) > 0.0 ? -1.0 : 1.0;
776 return((v*v/CPL_MATH_PI)*acos((f/v)*(1.0+e*(1.0-u*u)/(4.0*f*f))));
782 static double PSF_H2(
double f,
785 const double tmp1 = (2.0 * f) / (1.0 + u);
786 const double tmp2 = (1.0 - u) / (2.0 * f);
788 return -1.0 * (f/CPL_MATH_PI) * (1.0+u)
789 * sqrt((1.0-tmp1*tmp1)*(1.0-tmp2*tmp2));
795 static double PSF_G(
double f,
798 if (f <= (1.0-u)/2.0)
return(u*u);
799 if (f >= (1.0+u)/2.0)
return(0.0);
800 else return(PSF_H1(f,u,1.0) + PSF_H1(f,u,u) + PSF_H2(f,u));
812 static double PSF_sinc_norm(
double x)
814 return sin(x * CPL_MATH_PI) / (x * CPL_MATH_PI);
820 static double PSF_TelOTF(
double f,
823 return((PSF_G(f,1.0)+u*u*PSF_G(f/u,1.0)-2.0*PSF_G(f,u))/(1.0-u*u));
838 cpl_error_code irplib_strehl_disk_max(
const cpl_image *
self,
845 const int nx = cpl_image_get_size_x(
self);
846 const int ny = cpl_image_get_size_y(
self);
848 const int lx = (int)(xpos - radius);
849 const int ly = (int)(ypos - radius);
851 const int ux = (int)(xpos + radius) + 1;
852 const int uy = (int)(ypos + radius) + 1;
854 const double sqr = radius * radius;
855 cpl_boolean first = CPL_TRUE;
860 cpl_ensure_code(
self != NULL, CPL_ERROR_NULL_INPUT);
861 cpl_ensure_code(ppeak != NULL, CPL_ERROR_NULL_INPUT);
862 cpl_ensure_code(radius > 0.0, CPL_ERROR_ILLEGAL_INPUT);
865 for (j = IRPLIB_MAX(ly, 0); j < IRPLIB_MIN(uy, ny-1); j++) {
866 const double yj = (double)j - ypos;
867 for (i = IRPLIB_MAX(lx, 0); i < IRPLIB_MIN(ux, nx-1); i++) {
868 const double xi = (double)i - xpos;
869 const double dist = yj * yj + xi * xi;
872 const double value = cpl_image_get(
self, i+1, j+1, &isbad);
874 if (!isbad && irplib_isnan(value) == 0 &&
875 (first || value > *ppeak)) {
884 ? cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND)
888 #ifndef IRPLIB_NO_FIT_GAUSSIAN
889 #ifdef IRPLIB_STREHL_USE_CPL_IMAGE_FIT_GAUSSIAN
907 static double irplib_gaussian_2d(
double x,
915 return norm / (sig_x * sig_y * CPL_MATH_2PI *
916 exp(x * x / (2.0 * sig_x * sig_x) +
917 y * y / (2.0 * sig_y * sig_y)));
921 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(6, 9, 1)
944 double irplib_gaussian_eval_2d(
const cpl_array *
self,
double x,
double y)
946 cpl_errorstate prestate = cpl_errorstate_get();
947 const double B = cpl_array_get_double(
self, 0, NULL);
948 const double A = cpl_array_get_double(
self, 1, NULL);
949 const double R = cpl_array_get_double(
self, 2, NULL);
950 const double M_x = cpl_array_get_double(
self, 3, NULL);
951 const double M_y = cpl_array_get_double(
self, 4, NULL);
952 const double S_x = cpl_array_get_double(
self, 5, NULL);
953 const double S_y = cpl_array_get_double(
self, 6, NULL);
957 if (!cpl_errorstate_is_equal(prestate)) {
958 (void)cpl_error_set_where(cpl_func);
959 }
else if (cpl_array_get_size(
self) != 7) {
960 (void)cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
961 }
else if (fabs(R) < 1.0 && S_x != 0.0 && S_y != 0.0) {
962 const double x_n = (x - M_x) / S_x;
963 const double y_n = (y - M_y) / S_y;
965 value = B + A / (CPL_MATH_2PI * S_x * S_y * sqrt(1 - R * R)) *
966 exp(-0.5 / (1 - R * R) * ( x_n * x_n + y_n * y_n
967 - 2.0 * R * x_n * y_n));
968 }
else if (fabs(R) > 1.0) {
969 (void)cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
970 "fabs(R=%g) > 1", R);
972 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DIVISION_BY_ZERO,
973 "R=%g. Sigma=(%g, %g)", R, S_x, S_y);
988 static uint32_t irplib_roundup_power2(uint32_t v)
1013 cpl_error_code irplib_gaussian_maxpos(
const cpl_image *
self,
1020 const cpl_size nx = cpl_image_get_size_x(
self);
1021 const cpl_size ny = cpl_image_get_size_y(
self);
1025 const double median = cpl_image_get_median_dev(
self, &med_dist);
1026 cpl_mask * selection;
1027 cpl_size nlabels = 0;
1028 cpl_image * labels = NULL;
1029 cpl_apertures * aperts;
1033 cpl_size xposmax, yposmax;
1034 double xposcen, yposcen;
1035 double valmax, valfit = -1.0;
1036 #ifdef IRPLIB_STREHL_USE_CPL_IMAGE_FIT_GAUSSIAN
1037 double norm, xcen, ycen, sig_x, sig_y, fwhm_x, fwhm_y;
1039 cpl_array * gauss_parameters = NULL;
1040 cpl_errorstate prestate = cpl_errorstate_get();
1041 cpl_error_code code;
1044 cpl_ensure_code( sigma > 0.0, CPL_ERROR_ILLEGAL_INPUT);
1046 selection = cpl_mask_new(nx, ny);
1048 for (; iretry > 0 && nlabels == 0; iretry--, sigma *= 0.5) {
1051 const double threshold = median + sigma * med_dist;
1055 code = cpl_mask_threshold_image(selection,
self, threshold, DBL_MAX,
1061 cpl_image_delete(labels);
1062 labels = cpl_image_labelise_mask_create(selection, &nlabels);
1066 cpl_mask_delete(selection);
1069 cpl_image_delete(labels);
1070 return cpl_error_set_where(cpl_func);
1071 }
else if (nlabels == 0) {
1072 cpl_image_delete(labels);
1073 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
1076 aperts = cpl_apertures_new_from_image(
self, labels);
1081 npixobj = cpl_apertures_get_npix(aperts, ifluxapert);
1082 objradius = sqrt((
double)npixobj * CPL_MATH_1_PI);
1084 winsize = IRPLIB_MIN(IRPLIB_MIN(nx, ny), irplib_roundup_power2
1085 ((uint32_t)(3.0 * objradius + 0.5)));
1087 xposmax = cpl_apertures_get_maxpos_x(aperts, ifluxapert);
1088 yposmax = cpl_apertures_get_maxpos_y(aperts, ifluxapert);
1089 xposcen = cpl_apertures_get_centroid_x(aperts, ifluxapert);
1090 yposcen = cpl_apertures_get_centroid_y(aperts, ifluxapert);
1091 valmax = cpl_apertures_get_max(aperts, ifluxapert);
1093 cpl_apertures_delete(aperts);
1094 cpl_image_delete(labels);
1096 cpl_msg_debug(cpl_func,
"Object radius at S/R=%g: %g (window-size=%u)",
1097 sigma, objradius, (
unsigned)winsize);
1098 cpl_msg_debug(cpl_func,
"Object-peak @ (%d, %d) = %g", (
int)xposmax,
1099 (
int)yposmax, valmax);
1101 gauss_parameters = cpl_array_new(7, CPL_TYPE_DOUBLE);
1102 cpl_array_set_double(gauss_parameters, 0, median);
1104 code = cpl_fit_image_gaussian(
self, NULL, xposcen, yposcen,
1105 winsize, winsize, gauss_parameters,
1110 const double M_x = cpl_array_get_double(gauss_parameters, 3, NULL);
1111 const double M_y = cpl_array_get_double(gauss_parameters, 4, NULL);
1113 valfit = irplib_gaussian_eval_2d(gauss_parameters, M_x, M_y);
1115 if (!cpl_errorstate_is_equal(prestate)) {
1116 code = cpl_error_get_code();
1122 cpl_msg_debug(cpl_func,
"Gauss-fit @ (%g, %g) = %g",
1126 cpl_array_delete(gauss_parameters);
1128 #ifdef IRPLIB_STREHL_USE_CPL_IMAGE_FIT_GAUSSIAN
1129 if (code || valfit < valmax) {
1130 cpl_errorstate_set(prestate);
1132 code = cpl_image_fit_gaussian(
self, xposcen, yposcen,
1133 (
int)(2.0 * objradius),
1143 valfit = irplib_gaussian_2d(0.0, 0.0, norm, sig_x, sig_y);
1145 cpl_msg_debug(cpl_func,
"Gauss-Fit @ (%g, %g) = %g. norm=%g, "
1146 "sigma=(%g, %g)", xcen, ycen, valfit, norm,
1149 if (valfit > valmax) {
1158 if (code || valfit < valmax) {
1159 cpl_errorstate_set(prestate);
1165 return code ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;