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))
82irplib_strehl_generate_otf(
double,
double,
double,
double,
int,
double);
83static double PSF_H1(
double,
double,
double);
84static double PSF_H2(
double,
double);
85static double PSF_G(
double,
double);
86static double PSF_sinc_norm(
double);
87static double PSF_TelOTF(
double,
double);
89#ifndef IRPLIB_NO_FIT_GAUSSIAN
90#ifdef IRPLIB_STREHL_USE_CPL_IMAGE_FIT_GAUSSIAN
91static double irplib_gaussian_2d(
double,
double,
double,
double,
double);
94#if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(6, 9, 1)
95#define irplib_gaussian_eval_2d cpl_gaussian_eval_2d
97static double irplib_gaussian_eval_2d(
const cpl_array *,
double,
double);
100static uint32_t irplib_roundup_power2(uint32_t v) CPL_ATTR_CONST;
102static cpl_error_code irplib_gaussian_maxpos(
const cpl_image *,
110static cpl_error_code irplib_closeset_aperture(
const cpl_apertures *self,
153irplib_strehl_compute(
const cpl_image *im,
177 double star_radius, max_radius;
180 const double window_size = (double)(IRPLIB_STREHL_RAD_CENTRAL);
183 const double strehl_error_coefficient = CPL_MATH_PI * 0.007 / 0.0271;
187#ifndef IRPLIB_NO_FIT_GAUSSIAN
188 double xposfit = 0.0, yposfit = 0.0, peak = 0.0;
191 cpl_errorstate prestate = cpl_errorstate_get();
194 cpl_ensure_code(window_size > 0.0, CPL_ERROR_ILLEGAL_INPUT);
197 cpl_ensure_code(im != NULL, CPL_ERROR_NULL_INPUT);
198 cpl_ensure_code(strehl != NULL, CPL_ERROR_NULL_INPUT);
199 cpl_ensure_code(strehl_err != NULL, CPL_ERROR_NULL_INPUT);
200 cpl_ensure_code(star_bg != NULL, CPL_ERROR_NULL_INPUT);
201 cpl_ensure_code(star_peak != NULL, CPL_ERROR_NULL_INPUT);
202 cpl_ensure_code(star_flux != NULL, CPL_ERROR_NULL_INPUT);
203 cpl_ensure_code(psf_peak != NULL, CPL_ERROR_NULL_INPUT);
204 cpl_ensure_code(psf_flux != NULL, CPL_ERROR_NULL_INPUT);
206 cpl_ensure_code(pscale > 0.0, CPL_ERROR_ILLEGAL_INPUT);
208 cpl_ensure_code(r1 > 0.0, CPL_ERROR_ILLEGAL_INPUT);
209 cpl_ensure_code(r2 > 0.0, CPL_ERROR_ILLEGAL_INPUT);
210 cpl_ensure_code(r3 > r2, CPL_ERROR_ILLEGAL_INPUT);
216 psf = irplib_strehl_generate_psf(m1, m2, lam, dlam, pscale, size);
218 return cpl_error_set_where(cpl_func);
222 *psf_peak = cpl_image_get_max(psf);
223 cpl_image_delete(psf);
225 assert(*psf_peak > 0.0);
228#ifndef IRPLIB_NO_FIT_GAUSSIAN
229 code = irplib_gaussian_maxpos(im, IRPLIB_STREHL_DETECT_LEVEL, xpos, ypos,
230 &xposfit, &yposfit, &peak);
232 cpl_errorstate_set(prestate);
242 irplib_strehl_ring_background(im, xpos, ypos, r2 / pscale, r3 / pscale,
243 IRPLIB_BG_METHOD_AVER_REJ);
244 if (!cpl_errorstate_is_equal(prestate)) {
245 return cpl_error_set_where(cpl_func);
249 star_radius = r1 / pscale;
252 *star_flux = irplib_strehl_disk_flux(im, xpos, ypos, star_radius, *star_bg);
254 if (*star_flux <= 0.0) {
255 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
256 "Non-positive star flux=%g (Star "
258 *star_flux, *star_bg);
262 max_radius = window_size < star_radius ? window_size : star_radius;
263 cpl_ensure_code(!irplib_strehl_disk_max(im, xpos, ypos, max_radius,
265 cpl_error_get_code());
266 *star_peak -= *star_bg;
268 if (*star_flux <= 0.0) {
269 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
270 "Non-positive star peak=%g (Star "
271 "background=%g, Star flux=%g)",
272 *star_flux, *star_bg, *star_flux);
277 *strehl = (*star_peak * *psf_flux) / (*star_flux * *psf_peak);
279#ifndef IRPLIB_NO_FIT_GAUSSIAN
280 if (code == CPL_ERROR_NONE && peak > *star_peak && *star_peak > 0.0 &&
281 *strehl * peak / *star_peak <= 1.0) {
282 cpl_msg_debug(cpl_func,
"Increasing Strehl from %g: %g (%g)", *strehl,
283 *strehl * peak / *star_peak, peak / *star_peak);
284 *strehl *= peak / *star_peak;
292 ring[2] = r2 / pscale;
293 ring[3] = r3 / pscale;
295 while (cpl_flux_get_noise_ring(im, ring, noise_box_sz, noise_nsamples,
299 if (ring_tries > 0) {
300 cpl_errorstate_set(prestate);
303 return cpl_error_set_where(cpl_func);
306 *strehl_err = strehl_error_coefficient * (*bg_noise) * pscale *
307 star_radius * star_radius / *star_flux;
310 cpl_msg_warning(cpl_func,
311 "Extreme Strehl-ratio=%g (strehl-error=%g, "
312 "star_peak=%g, star_flux=%g, psf_peak=%g, psf_flux=%g)",
313 *strehl, *strehl_err, *star_peak, *star_flux, *psf_peak,
318 return *strehl_err >= 0.0
320 : cpl_error_set_message(
321 cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
322 "Negative strehl-error=%g (Strehl-ratio=%g, "
323 "star_peak=%g, star_flux=%g, psf_peak=%g, "
325 *strehl_err, *strehl, *star_peak, *star_flux, *psf_peak,
344irplib_strehl_disk_flux(
const cpl_image *im,
350 const int nx = cpl_image_get_size_x(im);
351 const int ny = cpl_image_get_size_y(im);
353 const int lx = (int)(xpos - rad);
354 const int ly = (int)(ypos - rad);
356 const int ux = (int)(xpos + rad) + 1;
357 const int uy = (int)(ypos + rad) + 1;
359 const double sqr = rad * rad;
365 cpl_ensure(im != NULL, CPL_ERROR_NULL_INPUT, 0.0);
366 cpl_ensure(rad > 0.0, CPL_ERROR_ILLEGAL_INPUT, 0.0);
368 for (j = IRPLIB_MAX(ly, 0); j < IRPLIB_MIN(uy, ny); j++) {
369 const double yj = (double)j - ypos;
370 for (i = IRPLIB_MAX(lx, 0); i < IRPLIB_MIN(ux, nx); i++) {
371 const double xi = (double)i - xpos;
372 const double dist = yj * yj + xi * xi;
375 const double value = cpl_image_get(im, i + 1, j + 1, &isbad);
401irplib_strehl_ring_background(
const cpl_image *im,
406 irplib_strehl_bg_method mode)
408 const int nx = cpl_image_get_size_x(im);
409 const int ny = cpl_image_get_size_y(im);
411 const int lx = (int)(xpos - rad_ext);
412 const int ly = (int)(ypos - rad_ext);
414 const int ux = (int)(xpos + rad_ext) + 1;
415 const int uy = (int)(ypos + rad_ext) + 1;
417 const double sqr_int = rad_int * rad_int;
418 const double sqr_ext = rad_ext * rad_ext;
424 cpl_ensure(im != NULL, CPL_ERROR_NULL_INPUT, 0.0);
425 cpl_ensure(rad_int > 0.0, CPL_ERROR_ILLEGAL_INPUT, 0.0);
426 cpl_ensure(rad_ext > rad_int, CPL_ERROR_ILLEGAL_INPUT, 0.0);
428 cpl_ensure(mode == IRPLIB_BG_METHOD_AVER_REJ ||
429 mode == IRPLIB_BG_METHOD_MEDIAN,
430 CPL_ERROR_UNSUPPORTED_MODE, 0.0);
432 mpix = (int)((2.0 * rad_ext + 1.0) * (2.0 * rad_ext + 1.0));
435 pix_arr = cpl_vector_new(mpix);
440 for (j = IRPLIB_MAX(ly, 0); j < IRPLIB_MIN(uy, ny); j++) {
441 const double yj = (double)j - ypos;
442 for (i = IRPLIB_MAX(lx, 0); i < IRPLIB_MIN(ux, nx); i++) {
443 const double xi = (double)i - xpos;
444 const double dist = yj * yj + xi * xi;
445 if (sqr_int <= dist && dist <= sqr_ext) {
447 const double value = cpl_image_get(im, i + 1, j + 1, &isbad);
450 cpl_vector_set(pix_arr, npix, value);
457 assert(npix <= mpix);
459 if (npix < IRPLIB_DISK_BG_MIN_PIX_NB) {
460 cpl_vector_delete(pix_arr);
461 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
463 "at least %d (not %d <= %d) samples to "
465 IRPLIB_DISK_BG_MIN_PIX_NB, npix, mpix);
472 pix_arr = cpl_vector_wrap(npix, (
double *)cpl_vector_unwrap(pix_arr));
474 if (mode == IRPLIB_BG_METHOD_AVER_REJ) {
475 const int low_ind = (int)((
double)npix * IRPLIB_DISK_BG_REJ_LOW);
477 (int)((
double)npix * (1.0 - IRPLIB_DISK_BG_REJ_HIGH));
480 cpl_vector_sort(pix_arr, CPL_SORT_ASCENDING);
482 for (i = low_ind; i < high_ind; i++) {
483 flux += cpl_vector_get(pix_arr, i);
485 if (high_ind - low_ind > 1)
486 flux /= (double)(high_ind - low_ind);
489 flux = cpl_vector_get_median(pix_arr);
492 cpl_vector_delete(pix_arr);
519irplib_strehl_generate_psf(
double m1,
526 cpl_image *otf_image =
527 irplib_strehl_generate_otf(m1, m2, lam, dlam, size, pscale);
529 if (otf_image == NULL ||
540 cpl_image_fft(otf_image, NULL, CPL_FFT_UNNORMALIZED) ||
543 cpl_image_abs(otf_image) ||
546 cpl_image_normalise(otf_image, CPL_NORM_FLUX)) {
547 (void)cpl_error_set_where(cpl_func);
548 cpl_image_delete(otf_image);
575irplib_strehl_generate_otf(
double m1,
584 const double obs_ratio = m1 != 0.0 ? m2 / m1 : 0.0;
586 const double rpscale = pscale * CPL_MATH_2PI / (double)(360 * 60 * 60);
588 const double f_max = m1 * rpscale * (double)size;
591 const int pix0 = size / 2;
595 cpl_ensure(m2 > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
596 cpl_ensure(m1 > m2, CPL_ERROR_ILLEGAL_INPUT, NULL);
597 cpl_ensure(dlam > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
598 cpl_ensure(pscale > 0.0, CPL_ERROR_ILLEGAL_INPUT, NULL);
599 cpl_ensure(size > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
601 cpl_ensure(size % 2 == 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
604 cpl_ensure(2.0 * lam > dlam, CPL_ERROR_ILLEGAL_INPUT, NULL);
611 otf_data = (
double *)cpl_malloc(size * size *
sizeof(*otf_data));
618 for (j = 0; j <= pix0; j++) {
619 double sinc_y_9 = 0.0;
620 for (i = 0; i <= j; i++) {
621 if (i == 0 && j == 0) {
622 otf_data[size * pix0 + pix0] = 1.0;
625 const double x = (double)i;
626 const double y = (double)j;
627 const double sqdist = x * x + y * y;
628 double f_lambda = 0.0;
629 double sinc_xy_9 = 0.0;
637 for (k = 4; k >= -4; k--) {
639 const double lambda = lam - dlam * (double)k / 8.0;
643 if (sqdist * lambda * lambda >= f_max * f_max)
647 f_lambda = sqrt(sqdist) / f_max;
650 sinc_xy_9 = sinc_y_9 =
651 PSF_sinc_norm(y / (
double)size) / 9.0;
655 sinc_y_9 * PSF_sinc_norm(x / (
double)size);
659 otfxy += PSF_TelOTF(f_lambda * lambda, obs_ratio);
665 otf_data[size * (pix0 - j) + pix0 - i] = otfxy;
666 otf_data[size * (pix0 - i) + pix0 - j] = otfxy;
668 otf_data[size * (pix0 - j) + pix0 + i] = otfxy;
669 otf_data[size * (pix0 + i) + pix0 - j] = otfxy;
671 otf_data[size * (pix0 + j) + pix0 - i] = otfxy;
672 otf_data[size * (pix0 - i) + pix0 + j] = otfxy;
673 otf_data[size * (pix0 + j) + pix0 + i] = otfxy;
674 otf_data[size * (pix0 + i) + pix0 + j] = otfxy;
681 return cpl_image_wrap_double(size, size, otf_data);
688PSF_H1(
double f,
double u,
double v)
690 const double e = fabs(1.0 - v) > 0.0 ? -1.0 : 1.0;
692 return ((v * v / CPL_MATH_PI) *
693 acos((f / v) * (1.0 + e * (1.0 - u * u) / (4.0 * f * f))));
700PSF_H2(
double f,
double u)
702 const double tmp1 = (2.0 * f) / (1.0 + u);
703 const double tmp2 = (1.0 - u) / (2.0 * f);
705 return -1.0 * (f / CPL_MATH_PI) * (1.0 + u) *
706 sqrt((1.0 - tmp1 * tmp1) * (1.0 - tmp2 * tmp2));
713PSF_G(
double f,
double u)
715 if (f <= (1.0 - u) / 2.0)
717 if (f >= (1.0 + u) / 2.0)
720 return (PSF_H1(f, u, 1.0) + PSF_H1(f, u, u) + PSF_H2(f, u));
733PSF_sinc_norm(
double x)
737 return x != 0.0 ? sin(x * CPL_MATH_PI) / (x * CPL_MATH_PI) : 1.0;
744PSF_TelOTF(
double f,
double u)
746 return ((PSF_G(f, 1.0) + u * u * PSF_G(f / u, 1.0) - 2.0 * PSF_G(f, u)) /
763irplib_strehl_disk_max(
const cpl_image *self,
769 const int nx = cpl_image_get_size_x(self);
770 const int ny = cpl_image_get_size_y(self);
772 const int lx = (int)(xpos - radius);
773 const int ly = (int)(ypos - radius);
775 const int ux = (int)(xpos + radius) + 1;
776 const int uy = (int)(ypos + radius) + 1;
778 const double sqr = radius * radius;
779 cpl_boolean first = CPL_TRUE;
784 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
785 cpl_ensure_code(ppeak != NULL, CPL_ERROR_NULL_INPUT);
786 cpl_ensure_code(radius > 0.0, CPL_ERROR_ILLEGAL_INPUT);
789 for (j = IRPLIB_MAX(ly, 0); j < IRPLIB_MIN(uy, ny); j++) {
790 const double yj = (double)j - ypos;
791 for (i = IRPLIB_MAX(lx, 0); i < IRPLIB_MIN(ux, nx); i++) {
792 const double xi = (double)i - xpos;
793 const double dist = yj * yj + xi * xi;
796 const double value = cpl_image_get(self, i + 1, j + 1, &isbad);
798 if (!isbad && (first || value > *ppeak)) {
806 return first ? cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND)
810#ifndef IRPLIB_NO_FIT_GAUSSIAN
811#ifdef IRPLIB_STREHL_USE_CPL_IMAGE_FIT_GAUSSIAN
830irplib_gaussian_2d(
double x,
double y,
double norm,
double sig_x,
double sig_y)
834 (sig_x * sig_y * CPL_MATH_2PI *
835 exp(x * x / (2.0 * sig_x * sig_x) + y * y / (2.0 * sig_y * sig_y)));
839#if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(6, 9, 1)
862irplib_gaussian_eval_2d(
const cpl_array *self,
double x,
double y)
864 cpl_errorstate prestate = cpl_errorstate_get();
865 const double B = cpl_array_get_double(self, 0, NULL);
866 const double A = cpl_array_get_double(self, 1, NULL);
867 const double R = cpl_array_get_double(self, 2, NULL);
868 const double M_x = cpl_array_get_double(self, 3, NULL);
869 const double M_y = cpl_array_get_double(self, 4, NULL);
870 const double S_x = cpl_array_get_double(self, 5, NULL);
871 const double S_y = cpl_array_get_double(self, 6, NULL);
875 if (!cpl_errorstate_is_equal(prestate)) {
876 (void)cpl_error_set_where(cpl_func);
878 else if (cpl_array_get_size(self) != 7) {
879 (void)cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
881 else if (fabs(R) < 1.0 && S_x != 0.0 && S_y != 0.0) {
882 const double x_n = (x - M_x) / S_x;
883 const double y_n = (y - M_y) / S_y;
885 value = B + A / (CPL_MATH_2PI * S_x * S_y * sqrt(1 - R * R)) *
886 exp(-0.5 / (1 - R * R) *
887 (x_n * x_n + y_n * y_n - 2.0 * R * x_n * y_n));
889 else if (fabs(R) > 1.0) {
890 (void)cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_OUTPUT,
891 "fabs(R=%g) > 1", R);
894 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DIVISION_BY_ZERO,
895 "R=%g. Sigma=(%g, %g)", R, S_x, S_y);
911irplib_roundup_power2(uint32_t v)
924irplib_closeset_aperture(
const cpl_apertures *self,
929 double dist = INFINITY;
931 const int nsize = cpl_apertures_get_size(self);
934 cpl_ensure_code(nsize > 0, cpl_error_get_code());
935 cpl_ensure_code(ind, CPL_ERROR_NULL_INPUT);
939 for (i = 1; i <= nsize; ++i) {
940 const double this_x = cpl_apertures_get_centroid_x(self, i);
941 const double this_y = cpl_apertures_get_centroid_y(self, i);
942 const double this_d_sq = pow(this_x - x, 2.0) + pow(this_y - y, 2.0);
944 if (this_d_sq < dist) {
949 return CPL_ERROR_NONE;
965irplib_gaussian_maxpos(
const cpl_image *self,
973 const cpl_size nx = cpl_image_get_size_x(self);
974 const cpl_size ny = cpl_image_get_size_y(self);
978 const double median = cpl_image_get_median_dev(self, &med_dist);
980 cpl_size nlabels = 0;
981 cpl_image *labels = NULL;
982 cpl_apertures *aperts;
986 cpl_size xposmax, yposmax;
987 double xposcen, yposcen;
988 double valmax, valfit = -1.0;
989#ifdef IRPLIB_STREHL_USE_CPL_IMAGE_FIT_GAUSSIAN
990 double norm, xcen, ycen, sig_x, sig_y, fwhm_x, fwhm_y;
992 cpl_array *gauss_parameters = NULL;
993 cpl_errorstate prestate = cpl_errorstate_get();
994 cpl_error_code code = CPL_ERROR_NONE;
997 cpl_ensure_code(sigma > 0.0, CPL_ERROR_ILLEGAL_INPUT);
999 selection = cpl_mask_new(nx, ny);
1001 for (; iretry > 0 && nlabels == 0; iretry--, sigma *= 0.5) {
1003 const double threshold = median + sigma * med_dist;
1007 code = cpl_mask_threshold_image(selection, self, threshold, DBL_MAX,
1014 cpl_image_delete(labels);
1015 labels = cpl_image_labelise_mask_create(selection, &nlabels);
1019 cpl_mask_delete(selection);
1022 cpl_image_delete(labels);
1023 return cpl_error_set_where(cpl_func);
1025 else if (nlabels == 0) {
1026 cpl_image_delete(labels);
1027 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
1030 aperts = cpl_apertures_new_from_image(self, labels);
1033 code = irplib_closeset_aperture(aperts, x_initial, y_initial, &ifluxapert);
1036 cpl_apertures_delete(aperts);
1037 cpl_image_delete(labels);
1038 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
1041 npixobj = cpl_apertures_get_npix(aperts, ifluxapert);
1042 objradius = sqrt((
double)npixobj * CPL_MATH_1_PI);
1045 IRPLIB_MIN(IRPLIB_MIN(nx, ny),
1046 irplib_roundup_power2((uint32_t)(3.0 * objradius + 0.5)));
1048 xposmax = cpl_apertures_get_maxpos_x(aperts, ifluxapert);
1049 yposmax = cpl_apertures_get_maxpos_y(aperts, ifluxapert);
1050 xposcen = cpl_apertures_get_centroid_x(aperts, ifluxapert);
1051 yposcen = cpl_apertures_get_centroid_y(aperts, ifluxapert);
1052 valmax = cpl_apertures_get_max(aperts, ifluxapert);
1054 cpl_apertures_delete(aperts);
1055 cpl_image_delete(labels);
1057 cpl_msg_debug(cpl_func,
"Object radius at S/R=%g: %g (window-size=%u)",
1058 sigma, objradius, (
unsigned)winsize);
1059 cpl_msg_debug(cpl_func,
"Object-peak @ (%d, %d) = %g", (
int)xposmax,
1060 (
int)yposmax, valmax);
1062 gauss_parameters = cpl_array_new(7, CPL_TYPE_DOUBLE);
1063 cpl_array_set_double(gauss_parameters, 0, median);
1065 code = cpl_fit_image_gaussian(self, NULL, xposcen, yposcen, winsize,
1066 winsize, gauss_parameters, NULL, NULL, NULL,
1067 NULL, NULL, NULL, NULL, NULL, NULL);
1069 const double M_x = cpl_array_get_double(gauss_parameters, 3, NULL);
1070 const double M_y = cpl_array_get_double(gauss_parameters, 4, NULL);
1072 valfit = irplib_gaussian_eval_2d(gauss_parameters, M_x, M_y);
1074 if (!cpl_errorstate_is_equal(prestate)) {
1075 code = cpl_error_get_code();
1082 cpl_msg_debug(cpl_func,
"Gauss-fit @ (%g, %g) = %g", M_x, M_y,
1086 cpl_array_delete(gauss_parameters);
1088#ifdef IRPLIB_STREHL_USE_CPL_IMAGE_FIT_GAUSSIAN
1089 if (code || valfit < valmax) {
1090 cpl_errorstate_set(prestate);
1092 code = cpl_image_fit_gaussian(self, xposcen, yposcen,
1093 (
int)(2.0 * objradius), &norm, &xcen,
1094 &ycen, &sig_x, &sig_y, &fwhm_x, &fwhm_y);
1097 valfit = irplib_gaussian_2d(0.0, 0.0, norm, sig_x, sig_y);
1099 cpl_msg_debug(cpl_func,
1100 "Gauss-Fit @ (%g, %g) = %g. norm=%g, "
1102 xcen, ycen, valfit, norm, sig_x, sig_y);
1104 if (valfit > valmax) {
1113 if (code || valfit < valmax) {
1114 cpl_errorstate_set(prestate);
1120 return code ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;