29 #include <cxmessages.h>
31 #include <cxstrutils.h>
33 #include <cpl_error.h>
34 #include <cpl_image.h>
35 #include <cpl_table.h>
36 #include <cpl_parameterlist.h>
41 #include "gimessages.h"
43 #include "gichebyshev.h"
45 #include "gipsfdata.h"
46 #include "gilocalization.h"
50 #include "gifiberutils.h"
63 PROFILE_PSFEXP = 1 << 1,
64 PROFILE_PSFEXP2 = 1 << 2,
65 PROFILE_GAUSSIAN = 1 << 3
68 typedef enum GiProfileId GiProfileId;
78 typedef struct GiPsfParams GiPsfParams;
89 typedef struct GiPsfBin GiPsfBin;
91 struct GiPsfParameterFit {
96 typedef struct GiPsfParameterFit GiPsfParameterFit;
131 _giraffe_psf_fit_profile1d(GiPsfParameterFit* result,
132 const GiPsfData* psfdata,
const cxchar* name,
133 const cpl_table* fibers, cxint order,
134 const GiClipParams* setup)
142 cpl_matrix* x = NULL;
143 cpl_matrix* base = NULL;
145 const cpl_image* parameter = NULL;
148 cx_assert(result != NULL);
149 cx_assert(result->coeffs != NULL);
150 cx_assert(result->fit != NULL);
151 cx_assert(psfdata != NULL && name != NULL);
152 cx_assert(fibers != NULL);
153 cx_assert(setup != NULL);
155 nb = giraffe_psfdata_bins(psfdata);
156 ns = giraffe_psfdata_fibers(psfdata);
157 nx = giraffe_psfdata_ysize(psfdata);
159 if (ns != cpl_table_get_nrow(fibers)) {
163 if ((cpl_image_get_size_x(result->fit) != ns) ||
164 (cpl_image_get_size_y(result->fit) != nx)) {
168 if ((cpl_matrix_get_nrow(result->coeffs) != order + 1) ||
169 (cpl_matrix_get_ncol(result->coeffs) != ns)) {
173 for (i = 0; i < ns; i++) {
175 register cxint j = 0;
176 register cxint valid_bins = 0;
178 for (j = 0; j < nb; j++) {
179 if (giraffe_psfdata_get_bin(psfdata, i, j) >= 0.) {
184 if (valid_bins < order + 1) {
195 x = cpl_matrix_new(nx, 1);
197 for (i = 0; i < nx; i++) {
198 cpl_matrix_set(x, i, 0, i);
201 base = giraffe_chebyshev_base1d(0., (cxdouble)nx, order + 1, x);
204 cpl_matrix_delete(x);
210 cpl_matrix_delete(x);
218 parameter = giraffe_psfdata_get_data(psfdata, name);
220 if (parameter == NULL) {
224 for (i = 0; i < ns; i++) {
232 const cxdouble* _parameter =
233 cpl_image_get_data_double_const(parameter);
236 cxdouble* _fit = cpl_image_get_data_double(result->fit);
238 cpl_matrix* y = NULL;
239 cpl_matrix* ydiff = NULL;
240 cpl_matrix* coeffs = NULL;
241 cpl_matrix* fit = NULL;
244 x = cpl_matrix_new(nb, 1);
245 y = cpl_matrix_new(1, nb);
246 ydiff = cpl_matrix_new(1, nb);
248 for (j = 0; j < nb; j++) {
250 cxdouble bin = giraffe_psfdata_get_bin(psfdata, i, j);
254 cpl_matrix_set(x, k, 0, bin);
255 cpl_matrix_set(y, 0, k, _parameter[j * ns + i]);
266 cpl_matrix_set_size(x, k, 1);
267 cpl_matrix_set_size(y, 1, k);
268 cpl_matrix_set_size(ydiff, 1, k);
270 ntotal = cpl_matrix_get_nrow(x);
273 while ((naccepted > 0) && (iteration < setup->iterations) &&
274 (ratio > setup->fraction)) {
278 cpl_matrix* _base = NULL;
281 if (coeffs != NULL) {
282 cpl_matrix_delete(coeffs);
287 cpl_matrix_delete(fit);
291 _base = giraffe_chebyshev_base1d(0., (cxdouble)nx, order + 1, x);
294 if (coeffs == NULL) {
295 cpl_matrix_delete(_base);
299 cpl_matrix_delete(_base);
302 fit = cpl_matrix_product_create(coeffs, base);
304 for (j = 0; j < cpl_matrix_get_nrow(x); j++) {
306 cxint xlower = (cxint) ceil(cpl_matrix_get(x, j, 0));
307 cxint xupper = (cxint) floor(cpl_matrix_get(x, j, 0));
309 cxdouble ylower = cpl_matrix_get(fit, 0, xlower);
310 cxdouble yupper = cpl_matrix_get(fit, 0, xupper);
311 cxdouble yfit = (yupper + ylower) / 2.;
313 cpl_matrix_set(ydiff, 0, j, cpl_matrix_get(y, 0, j) - yfit);
325 for (j = 0; j < cpl_matrix_get_ncol(ydiff); j++) {
326 if (fabs(cpl_matrix_get(ydiff, 0, j)) <= sigma) {
327 cpl_matrix_set(x, k, 0, cpl_matrix_get(x, j, 0));
328 cpl_matrix_set(y, 0, k, cpl_matrix_get(y, 0, j));
333 cpl_matrix_set_size(x, k, 1);
334 cpl_matrix_set_size(y, 1, k);
335 cpl_matrix_set_size(ydiff, 1, k);
345 if (k == naccepted) {
350 ratio = (cxdouble)naccepted / (cxdouble) ntotal;
362 cx_assert(cpl_matrix_get_ncol(coeffs) == order + 1);
364 for (j = 0; j < cpl_matrix_get_ncol(coeffs); j++) {
365 cpl_matrix_set(result->coeffs, j, i,
366 cpl_matrix_get(coeffs, 0, j));
369 for (j = 0; j < nx; j++) {
370 _fit[j * ns + i] = cpl_matrix_get(fit, 0, j);
378 cpl_matrix_delete(x);
381 cpl_matrix_delete(y);
384 cpl_matrix_delete(ydiff);
387 cpl_matrix_delete(coeffs);
390 cpl_matrix_delete(fit);
395 cpl_matrix_delete(base);
447 _giraffe_psf_fit_profile2d(GiPsfParameterFit* result,
const cpl_table* fibers,
448 const cpl_image* psfdata,
const cpl_image* xbin,
449 const cpl_image* ybin, cxint xorder, cxint yorder,
450 const cpl_image* yfit, cxint ystart, cxint yend,
451 const GiClipParams* setup)
465 cxint ncx = xorder + 1;
466 cxint ncy = yorder + 1;
470 cpl_matrix* x = NULL;
471 cpl_matrix* y = NULL;
472 cpl_matrix* z = NULL;
473 cpl_matrix* zdiff = NULL;
474 cpl_matrix* nbins = NULL;
476 GiChebyshev2D* fit = NULL;
479 cx_assert(result != NULL);
480 cx_assert(result->coeffs != NULL);
481 cx_assert(result->fit != NULL);
482 cx_assert(fibers != NULL);
483 cx_assert(psfdata != NULL);
484 cx_assert(xbin != NULL && ybin != NULL);
485 cx_assert(yfit != NULL);
486 cx_assert(setup != NULL);
488 nb = cpl_image_get_size_y(xbin);
489 ns = cpl_image_get_size_x(xbin);
490 nx = cpl_image_get_size_y(result->fit);
492 if (ns != cpl_table_get_nrow(fibers)) {
496 if ((cpl_image_get_size_x(result->fit) != ns) ||
497 (cpl_image_get_size_y(result->fit) != nx)) {
501 if ((cpl_matrix_get_nrow(result->coeffs) != ncx) ||
502 (cpl_matrix_get_ncol(result->coeffs) != ncy)) {
506 for (i = 0; i < ns; i++) {
508 register cxint j = 0;
509 register cxint valid_bins = 0;
511 const cxdouble* _xbin = cpl_image_get_data_double_const(xbin);
513 for (j = 0; j < nb; j++) {
514 if (_xbin[j * ns + i] >= 0.) {
519 if (valid_bins < ncx * ncy) {
530 x = cpl_matrix_new(nb * ns, 1);
531 y = cpl_matrix_new(nb * ns, 1);
532 z = cpl_matrix_new(1, nb * ns);
533 zdiff = cpl_matrix_new(1, nb * ns);
534 nbins = cpl_matrix_new(nb * ns, 1);
536 for (i = 0; i < ns; i++) {
538 register cxint j = 0;
540 const cxdouble* _xbin = cpl_image_get_data_double_const(xbin);
541 const cxdouble* _ybin = cpl_image_get_data_double_const(ybin);
542 const cxdouble* _zbin = cpl_image_get_data_double_const(psfdata);
545 for ( j = 0; j < nb; j++) {
547 register cxint l = j * ns + i;
550 if (_xbin[l] >= 0.) {
551 cpl_matrix_set(nbins, k, 0, nspectra);
552 cpl_matrix_set(x, k, 0, _xbin[l]);
553 cpl_matrix_set(y, k, 0, _ybin[l]);
554 cpl_matrix_set(z, 0, k, _zbin[l]);
569 cpl_matrix_set_size(x, k, 1);
570 cpl_matrix_set_size(y, k, 1);
571 cpl_matrix_set_size(z, 1, k);
572 cpl_matrix_set_size(zdiff, 1, k);
573 cpl_matrix_set_size(nbins, k, 1);
575 ntotal = cpl_matrix_get_nrow(x);
578 while ((naccepted > 0) && (iteration < setup->iterations) &&
579 (ratio > setup->fraction))
584 cpl_matrix* base = NULL;
585 cpl_matrix* coeffs = NULL;
586 cpl_matrix* _coeffs = NULL;
588 register cxdouble* _pfit = cpl_image_get_data_double(result->fit);
591 base = giraffe_chebyshev_base2d(0., ystart, nx, yend, ncx, ncy, x, y);
594 cpl_matrix_delete(nbins);
597 cpl_matrix_delete(zdiff);
600 cpl_matrix_delete(z);
603 cpl_matrix_delete(y);
606 cpl_matrix_delete(x);
614 if (_coeffs == NULL) {
615 cpl_matrix_delete(base);
618 cpl_matrix_delete(nbins);
621 cpl_matrix_delete(zdiff);
624 cpl_matrix_delete(z);
627 cpl_matrix_delete(y);
630 cpl_matrix_delete(x);
636 cpl_matrix_delete(base);
645 coeffs = cpl_matrix_wrap(xorder + 1, yorder + 1,
646 cpl_matrix_get_data(_coeffs));
649 giraffe_chebyshev2d_delete(fit);
653 fit = giraffe_chebyshev2d_new(xorder, yorder);
654 status = giraffe_chebyshev2d_set(fit, 0., nx, ystart, yend, coeffs);
657 giraffe_chebyshev2d_delete(fit);
660 cpl_matrix_unwrap(coeffs);
663 cpl_matrix_delete(_coeffs);
666 cpl_matrix_delete(nbins);
669 cpl_matrix_delete(zdiff);
672 cpl_matrix_delete(z);
675 cpl_matrix_delete(y);
678 cpl_matrix_delete(x);
684 cpl_matrix_unwrap(coeffs);
687 cpl_matrix_delete(_coeffs);
698 for (i = 0; i < ns; i++) {
700 register cxint j = 0;
702 register const cxdouble* _yfit =
703 cpl_image_get_data_double_const(yfit);
705 for (j = 0; j < nx; j++) {
707 register cxint l = j * ns + i;
709 _pfit[l] = giraffe_chebyshev2d_eval(fit, j, _yfit[l]);
715 for (i = 0; i < cpl_matrix_get_nrow(x); i++) {
717 cxint n = cpl_matrix_get(nbins, i, 0);
718 cxint lower = (cxint) ceil(cpl_matrix_get(x, i, 0)) * ns + n;
719 cxint upper = (cxint) floor(cpl_matrix_get(x, i, 0)) * ns + n;
721 cxdouble zfit = (_pfit[lower] + _pfit[upper]) / 2.;
723 cpl_matrix_set(zdiff, 0, i, cpl_matrix_get(z, 0, i) - zfit);
730 for (i = 0; i < cpl_matrix_get_ncol(zdiff); i++) {
731 if (fabs(cpl_matrix_get(zdiff, 0, i)) <= sigma) {
732 cpl_matrix_set(x, k, 0, cpl_matrix_get(x, i, 0));
733 cpl_matrix_set(y, k, 0, cpl_matrix_get(y, i, 0));
734 cpl_matrix_set(z, 0, k, cpl_matrix_get(z, 0, i));
735 cpl_matrix_set(nbins, k, 0, cpl_matrix_get(nbins, i, 0));
740 cpl_matrix_set_size(x, k, 1);
741 cpl_matrix_set_size(y, k, 1);
742 cpl_matrix_set_size(z, 1, k);
743 cpl_matrix_set_size(zdiff, 1, k);
744 cpl_matrix_set_size(nbins, k, 1);
754 if (k == naccepted) {
759 ratio = (cxdouble)naccepted / (cxdouble) ntotal;
770 for (i = 0; i < cpl_matrix_get_nrow(result->coeffs); i++) {
772 register cxint j = 0;
774 const cpl_matrix* c = giraffe_chebyshev2d_coeffs(fit);
777 for (j = 0; j < cpl_matrix_get_ncol(result->coeffs); j++) {
778 cpl_matrix_set(result->coeffs, i, j, cpl_matrix_get(c, i, j));
788 giraffe_chebyshev2d_delete(fit);
791 cpl_matrix_delete(nbins);
794 cpl_matrix_delete(zdiff);
797 cpl_matrix_delete(z);
800 cpl_matrix_delete(y);
803 cpl_matrix_delete(x);
837 _giraffe_psf_compute_profile(GiPsfData* result, cpl_image* zraw,
838 cpl_image* zvar, cpl_image* locy,
839 cpl_image* locw, cpl_table* fibers,
840 cpl_image* bpm, GiModel* profile,
844 const cxchar* model = NULL;
845 const cxchar* ridx = NULL;
847 const cxdouble cutoff = log(config->limit);
860 cpl_matrix* mx = NULL;
861 cpl_matrix* my = NULL;
862 cpl_matrix* ms = NULL;
864 cpl_image* zx = NULL;
865 cpl_image* zv = NULL;
867 GiProfileId psfmodel = 0;
870 cx_assert(result != NULL);
871 cx_assert((zraw != NULL) && (zvar != NULL));
872 cx_assert((locy != NULL) && (locw != NULL));
873 cx_assert(fibers != NULL);
874 cx_assert(profile != NULL);
875 cx_assert(config != NULL);
877 cx_assert(cpl_image_get_size_x(zraw) == cpl_image_get_size_x(zvar));
878 cx_assert(cpl_image_get_size_y(zraw) == cpl_image_get_size_y(zvar));
880 cx_assert(cpl_image_get_size_x(locy) == cpl_image_get_size_x(locw));
881 cx_assert(cpl_image_get_size_y(locy) == cpl_image_get_size_y(locw));
884 nx = cpl_image_get_size_y(zraw);
885 ny = cpl_image_get_size_x(zraw);
886 ns = cpl_table_get_nrow(fibers);
888 nbins = (cxint) giraffe_psfdata_bins(result);
890 if (ns != cpl_image_get_size_x(locy)) {
894 if ((bpm != NULL) && (cpl_image_get_type(bpm) != CPL_TYPE_INT)) {
898 if (giraffe_psfdata_fibers(result) != (cxsize) ns) {
902 if ((giraffe_psfdata_xsize(result) != (cxsize) ny) ||
903 (giraffe_psfdata_ysize(result) != (cxsize) nx)) {
913 model = giraffe_model_get_name(profile);
915 if (strcmp(model,
"psfexp") == 0) {
916 psfmodel = PROFILE_PSFEXP;
918 else if (strcmp(model,
"psfexp2") == 0) {
919 psfmodel = PROFILE_PSFEXP2;
921 else if (strcmp(model,
"gaussian") == 0) {
922 psfmodel = PROFILE_GAUSSIAN;
929 if (config->normalize != FALSE) {
934 cxdouble* zsum = cx_calloc(nx,
sizeof(cxdouble));
944 for (x = 0; x < nx; x++) {
946 register cxint y = 0;
948 register const cxdouble* _zraw =
949 cpl_image_get_data_double(zraw);
952 for (y = 0; y < ny; y++) {
953 zsum[x] += _zraw[x * ny + y];
956 if (zsum[x] > zmax) {
964 for (x = 0; x < nx; x++) {
966 register cxint y = 0;
967 register const cxint* _bpm = cpl_image_get_data_int(bpm);
969 register const cxdouble* _zraw =
970 cpl_image_get_data_double(zraw);
973 for (y = 0; y < ny; y++) {
974 register cxint i = x * ny + y;
981 if (zsum[x] > zmax) {
994 zx = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
995 zv = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
998 for (x = 0; x < nx; x++) {
1000 register cxint y = 0;
1002 register cxdouble scale = zmax / zsum[x];
1003 register const cxdouble* _zraw = cpl_image_get_data_double(zraw);
1004 register const cxdouble* _zvar = cpl_image_get_data_double(zvar);
1005 register cxdouble* _zx = cpl_image_get_data_double(zx);
1006 register cxdouble* _zv = cpl_image_get_data_double(zv);
1008 for(y = 0; y < nx; y++) {
1009 register cxint i = x * ny + y;
1011 _zx[i] = _zraw[i] * scale;
1012 _zv[i] = _zvar[i] * scale;
1032 giraffe_error_push();
1034 exponent = giraffe_model_get_parameter(profile,
"Width2");
1036 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1040 giraffe_error_pop();
1057 mx = cpl_matrix_new(nbins * config->mwidth, 1);
1058 my = cpl_matrix_new(nbins * config->mwidth, 1);
1059 ms = cpl_matrix_new(nbins * config->mwidth, 1);
1061 if ((mx == NULL) || (my == NULL) || (ms == NULL)) {
1062 if (config->normalize == TRUE) {
1063 cpl_image_delete(zx);
1066 cpl_image_delete(zv);
1071 cpl_matrix_delete(mx);
1076 cpl_matrix_delete(my);
1081 cpl_matrix_delete(ms);
1094 giraffe_psfdata_set_model(result, giraffe_model_get_name(profile));
1096 for (n = 0; n < giraffe_model_count_parameters(profile); n++) {
1098 const cxchar* name = giraffe_model_parameter_name(profile, n);
1100 cpl_image* values = cpl_image_new(ns, nbins, CPL_TYPE_DOUBLE);
1102 if ((name == NULL) || (values == NULL)) {
1104 giraffe_psfdata_clear(result);
1106 cpl_matrix_delete(mx);
1109 cpl_matrix_delete(my);
1112 cpl_matrix_delete(ms);
1115 if (config->normalize == TRUE) {
1116 cpl_image_delete(zx);
1119 cpl_image_delete(zv);
1126 giraffe_psfdata_set_data(result, name, values);
1135 for (fiber = 0; fiber < ns; fiber++) {
1139 cxint cs = cpl_table_get_int(fibers, ridx, fiber, NULL) - 1;
1140 const cxint* _bpm = NULL;
1142 const cxdouble* _locy = cpl_image_get_data_double(locy);
1143 const cxdouble* _locw = cpl_image_get_data_double(locw);
1144 const cxdouble* _zx = cpl_image_get_data_double(zx);
1145 const cxdouble* _zv = cpl_image_get_data_double(zv);
1149 _bpm = cpl_image_get_data_int(bpm);
1157 for (x = 0, bin = 0; x < nx; x += config->bsize, bin++) {
1159 register cxint k = 0;
1160 register cxint xx = 0;
1164 cxint iterations = giraffe_model_get_iterations(profile);
1166 cxdouble amplitude = 0.;
1167 cxdouble bckground = 0.;
1168 cxdouble center = 0.;
1169 cxdouble width1 = 0.;
1170 cxdouble width2 = 0.;
1172 GiPsfBin xbin = {0., 0., 0., 0., 0.};
1179 for (k = 0, xx = x; (k < config->bsize) && (xx < nx); k++, xx++) {
1181 register cxint y = 0;
1182 register cxint l = xx * ns + cs;
1183 register cxint m = xx * ny;
1185 cxdouble zxmin = CX_MAXDOUBLE;
1186 cxdouble zxmax = 0.;
1187 cxdouble swidth = CX_MIN(_locw[l], config->mwidth);
1188 cxdouble ylo = (cxint) floor(_locy[l] - swidth);
1189 cxdouble yup = (cxint) ceil(_locy[l] + swidth);
1190 cxdouble ycenter = _locy[l];
1193 ylo = CX_MAX(0., ylo);
1194 yup = CX_MIN(ny, yup);
1198 for (y = ylo; y < yup; y++) {
1200 register cxint i = m + y;
1202 cpl_matrix_set(mx, ndata, 0, (cxdouble)y - ycenter);
1203 cpl_matrix_set(my, ndata, 0, _zx[i]);
1204 cpl_matrix_set(ms, ndata, 0, sqrt(_zv[i]));
1206 if (_zx[i] > zxmax) {
1210 if (_zx[i] < zxmin) {
1221 for (y = ylo; y < yup; y++) {
1223 register cxint i = m + y;
1226 cpl_matrix_set(mx, ndata, 0,
1227 (cxdouble)y - ycenter);
1228 cpl_matrix_set(my, ndata, 0, _zx[i]);
1229 cpl_matrix_set(ms, ndata, 0, sqrt(_zv[i]));
1231 if (_zx[i] > zxmax) {
1235 if (_zx[i] < zxmin) {
1249 xbin.ycenter += ycenter;
1250 xbin.ywidth += swidth;
1270 xbin.zmin = CX_MAX(0., xbin.zmin);
1277 giraffe_model_set_parameter(profile,
"Amplitude",
1278 xbin.zmax - xbin.zmin);
1279 giraffe_model_set_parameter(profile,
"Center", 0.);
1280 giraffe_model_set_parameter(profile,
"Background", xbin.zmin);
1283 case PROFILE_PSFEXP:
1284 width1 = pow(xbin.ywidth, exponent) / cutoff;
1285 giraffe_model_set_parameter(profile,
"Width2", exponent);
1288 case PROFILE_PSFEXP2:
1289 width1 = xbin.ywidth / pow(cutoff, 1. / exponent);
1290 giraffe_model_set_parameter(profile,
"Width2", exponent);
1293 case PROFILE_GAUSSIAN:
1294 width1 = xbin.ywidth / pow(cutoff, 0.5);
1301 giraffe_model_set_parameter(profile,
"Width1", width1);
1308 status = giraffe_model_fit_sequence(profile, mx, my, ms,
1311 amplitude = giraffe_model_get_parameter(profile,
"Amplitude");
1312 bckground = giraffe_model_get_parameter(profile,
"Background");
1313 center = giraffe_model_get_parameter(profile,
"Center");
1314 width1 = giraffe_model_get_parameter(profile,
"Width1");
1316 if ((psfmodel == PROFILE_PSFEXP) ||
1317 (psfmodel == PROFILE_PSFEXP2)) {
1318 width2 = giraffe_model_get_parameter(profile,
"Width2");
1327 if ((status != 0) ||
1328 (giraffe_model_get_position(profile) >= iterations) ||
1329 (amplitude <= 0.) ||
1341 giraffe_psfdata_set_bin(result, fiber, bin, xbin.xcenter);
1343 giraffe_psfdata_set(result,
"Amplitude", fiber, bin, amplitude);
1344 giraffe_psfdata_set(result,
"Center", fiber, bin,
1345 xbin.ycenter + center);
1346 giraffe_psfdata_set(result,
"Background", fiber, bin, bckground);
1347 giraffe_psfdata_set(result,
"Width1", fiber, bin, width1);
1349 if ((psfmodel == PROFILE_PSFEXP) ||
1350 (psfmodel == PROFILE_PSFEXP2)) {
1351 giraffe_psfdata_set(result,
"Width2", fiber, bin, width2);
1365 cpl_matrix_delete(mx);
1368 cpl_matrix_delete(my);
1371 cpl_matrix_delete(ms);
1374 if (config->normalize == TRUE) {
1375 cpl_image_delete(zx);
1378 cpl_image_delete(zv);
1414 _giraffe_psf_refine_profile(GiPsfData* result,
const GiPsfData* psfdata,
1415 cpl_image* zraw, cpl_image* zvar,
1416 cpl_table* fibers, cpl_image* bpm,
1417 GiModel* profile, GiPsfParams* config)
1420 const cxchar* model = NULL;
1422 const cxdouble cutoff = log(config->limit);
1434 cpl_matrix* mx = NULL;
1435 cpl_matrix* my = NULL;
1436 cpl_matrix* ms = NULL;
1438 GiProfileId psfmodel = 0;
1441 cx_assert(result != NULL);
1442 cx_assert(psfdata != NULL);
1443 cx_assert((zraw != NULL) && (zvar != NULL));
1444 cx_assert(fibers != NULL);
1445 cx_assert(profile != NULL);
1446 cx_assert(config != NULL);
1448 cx_assert(cpl_image_get_size_x(zraw) == cpl_image_get_size_x(zvar));
1449 cx_assert(cpl_image_get_size_y(zraw) == cpl_image_get_size_y(zvar));
1452 nx = cpl_image_get_size_y(zraw);
1453 ny = cpl_image_get_size_x(zraw);
1454 ns = cpl_table_get_nrow(fibers);
1456 if ((bpm != NULL) && (cpl_image_get_type(bpm) != CPL_TYPE_INT)) {
1460 if ((giraffe_psfdata_fibers(result) != (cxsize) ns) ||
1461 (giraffe_psfdata_bins(result) != (cxsize) nx)) {
1465 if ((giraffe_psfdata_xsize(result) != (cxsize) ny) ||
1466 (giraffe_psfdata_ysize(result) != (cxsize) nx)) {
1470 nbins = giraffe_psfdata_bins(result);
1472 if ((giraffe_psfdata_fibers(psfdata) != (cxsize) ns)) {
1476 if ((giraffe_psfdata_xsize(psfdata) != (cxsize) ny) ||
1477 (giraffe_psfdata_ysize(psfdata) != (cxsize) nx)) {
1481 binsize = nx / giraffe_psfdata_bins(psfdata);
1489 model = giraffe_model_get_name(profile);
1491 if (strcmp(model,
"psfexp") == 0) {
1492 psfmodel = PROFILE_PSFEXP;
1494 else if (strcmp(model,
"psfexp2") == 0) {
1495 psfmodel = PROFILE_PSFEXP2;
1497 else if (strcmp(model,
"gaussian") == 0) {
1498 psfmodel = PROFILE_GAUSSIAN;
1511 mx = cpl_matrix_new(nbins * config->mwidth, 1);
1512 my = cpl_matrix_new(nbins * config->mwidth, 1);
1513 ms = cpl_matrix_new(nbins * config->mwidth, 1);
1515 if ((mx == NULL) || (my == NULL) || (ms == NULL)) {
1518 cpl_matrix_delete(mx);
1523 cpl_matrix_delete(my);
1528 cpl_matrix_delete(ms);
1542 giraffe_psfdata_set_model(result, giraffe_model_get_name(profile));
1544 for (n = 0; n < giraffe_model_count_parameters(profile); n++) {
1546 const cxchar* name = giraffe_model_parameter_name(profile, n);
1548 cpl_image* values = cpl_image_new(ns, nbins, CPL_TYPE_DOUBLE);
1551 if ((name == NULL) || (values == NULL)) {
1553 giraffe_psfdata_clear(result);
1555 cpl_matrix_delete(mx);
1558 cpl_matrix_delete(my);
1561 cpl_matrix_delete(ms);
1568 giraffe_psfdata_set_data(result, name, values);
1577 for (fiber = 0; fiber < ns; fiber++) {
1580 const cxint* _bpm = NULL;
1582 const cxdouble* _zx = cpl_image_get_data_double(zraw);
1583 const cxdouble* _zv = cpl_image_get_data_double(zvar);
1587 _bpm = cpl_image_get_data_int(bpm);
1595 for (x = 0; x < nx; x++) {
1597 register cxint y = 0;
1598 register cxint m = x * ny;
1599 register cxint bin = CX_MAX(0, CX_MIN((cxint) floor(x / binsize),
1604 cxint iterations = giraffe_model_get_iterations(profile);
1606 cxdouble xcenter = 0.;
1607 cxdouble ycenter = 0.;
1608 cxdouble swidth = 0.;
1611 cxdouble amplitude = giraffe_psfdata_get(psfdata,
"Amplitude",
1613 cxdouble bckground = giraffe_psfdata_get(psfdata,
"Background",
1615 cxdouble center = giraffe_psfdata_get(psfdata,
"Center",
1617 cxdouble width1 = giraffe_psfdata_get(psfdata,
"Width1",
1619 cxdouble width2 = 0.;
1623 case PROFILE_PSFEXP:
1624 width2 = giraffe_psfdata_get(psfdata,
"Width2",
1626 swidth = pow(width1 * cutoff, 1./ width2);
1629 case PROFILE_PSFEXP2:
1630 width2 = giraffe_psfdata_get(psfdata,
"Width2",
1632 swidth = width1 * pow(cutoff, 1./ width2);
1635 case PROFILE_GAUSSIAN:
1636 swidth = width1 * pow(cutoff, 0.5);
1643 swidth = CX_MIN(swidth, config->mwidth);
1645 ylo = (cxint) floor(center - swidth);
1646 ylo = CX_MAX(0., ylo);
1648 yup = (cxint) ceil(center + swidth);
1649 yup = CX_MIN(ny, yup);
1653 for (y = ylo; y < yup; y++) {
1655 register cxint i = m + y;
1657 cpl_matrix_set(mx, ndata, 0, (cxdouble)y - center);
1658 cpl_matrix_set(my, ndata, 0, _zx[i]);
1659 cpl_matrix_set(ms, ndata, 0, sqrt(_zv[i]));
1668 for (y = ylo; y < yup; y++) {
1670 register cxint i = m + y;
1673 cpl_matrix_set(mx, ndata, 0, (cxdouble)y - center);
1674 cpl_matrix_set(my, ndata, 0, _zx[i]);
1675 cpl_matrix_set(ms, ndata, 0, sqrt(_zv[i]));
1689 bckground = CX_MAX(0., bckground);
1696 giraffe_model_set_parameter(profile,
"Amplitude", amplitude);
1697 giraffe_model_set_parameter(profile,
"Center", 0.);
1698 giraffe_model_set_parameter(profile,
"Background", bckground);
1699 giraffe_model_set_parameter(profile,
"Width1", width1);
1702 case PROFILE_PSFEXP:
1703 giraffe_model_set_parameter(profile,
"Width2", width2);
1706 case PROFILE_PSFEXP2:
1707 giraffe_model_set_parameter(profile,
"Width2", width2);
1710 case PROFILE_GAUSSIAN:
1722 status = giraffe_model_fit_sequence(profile, mx, my, ms,
1725 amplitude = giraffe_model_get_parameter(profile,
"Amplitude");
1726 bckground = giraffe_model_get_parameter(profile,
"Background");
1727 ycenter = giraffe_model_get_parameter(profile,
"Center");
1728 width1 = giraffe_model_get_parameter(profile,
"Width1");
1730 if ((psfmodel == PROFILE_PSFEXP) ||
1731 (psfmodel == PROFILE_PSFEXP2)) {
1732 width2 = giraffe_model_get_parameter(profile,
"Width2");
1742 if ((status != 0) ||
1743 (giraffe_model_get_position(profile) >= iterations) ||
1744 (amplitude <= 0.) ||
1759 giraffe_psfdata_set_bin(result, fiber, x, xcenter);
1761 giraffe_psfdata_set(result,
"Amplitude", fiber, x, amplitude);
1762 giraffe_psfdata_set(result,
"Center", fiber, x,
1764 giraffe_psfdata_set(result,
"Background", fiber, x, bckground);
1765 giraffe_psfdata_set(result,
"Width1", fiber, x, width1);
1767 if ((psfmodel == PROFILE_PSFEXP) ||
1768 (psfmodel == PROFILE_PSFEXP2)) {
1769 giraffe_psfdata_set(result,
"Width2", fiber, x, width2);
1783 cpl_matrix_delete(mx);
1786 cpl_matrix_delete(my);
1789 cpl_matrix_delete(ms);
1814 inline static GiPsfData*
1815 _giraffe_psf_fit_parameters1d(
const GiPsfData* psfdata,
1816 const cpl_table* fibers,
1817 const cxchar** names,
1819 const GiClipParams* setup)
1828 GiPsfData* psffit = NULL;
1831 cx_assert(psfdata != NULL);
1832 cx_assert(fibers != NULL);
1833 cx_assert(setup != NULL);
1835 ns = giraffe_psfdata_fibers(psfdata);
1836 nx = giraffe_psfdata_ysize(psfdata);
1837 ny = giraffe_psfdata_xsize(psfdata);
1839 psffit = giraffe_psfdata_create(ns, nx, ny, nx);
1841 giraffe_psfdata_set_model(psffit, giraffe_psfdata_get_model(psfdata));
1850 for (i = 0; i < ns; i++) {
1852 register cxint j = 0;
1854 for (j = 0; j < nx; j++) {
1855 giraffe_psfdata_set_bin(psffit, i, j, j);
1861 if (names == NULL) {
1864 cxsize count = giraffe_psfdata_parameters(psfdata);
1866 for (j = 0; j < count; j++) {
1868 const cxchar* name = giraffe_psfdata_get_name(psfdata, j);
1870 GiPsfParameterFit pfit = {NULL, NULL};
1873 pfit.fit = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
1874 pfit.coeffs = cpl_matrix_new(order + 1, ns);
1876 status = _giraffe_psf_fit_profile1d(&pfit, psfdata, name,
1877 fibers, order, setup);
1880 cpl_matrix_delete(pfit.coeffs);
1883 cpl_image_delete(pfit.fit);
1886 giraffe_psfdata_delete(psffit);
1892 giraffe_psfdata_set_data(psffit, name, pfit.fit);
1895 cpl_matrix_delete(pfit.coeffs);
1911 while (names[i] != NULL) {
1913 if (giraffe_psfdata_contains(psfdata, names[i]) == TRUE) {
1915 GiPsfParameterFit pfit = {NULL, NULL};
1918 pfit.fit = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
1919 pfit.coeffs = cpl_matrix_new(order + 1, ns);
1921 status = _giraffe_psf_fit_profile1d(&pfit, psfdata, names[i],
1922 fibers, order, setup);
1925 cpl_matrix_delete(pfit.coeffs);
1928 cpl_image_delete(pfit.fit);
1931 giraffe_psfdata_delete(psffit);
1937 giraffe_psfdata_set_data(psffit, names[i], pfit.fit);
1940 cpl_matrix_delete(pfit.coeffs);
1970 inline static GiPsfData*
1971 _giraffe_psf_fit_parameters(
const GiPsfData* psfdata,
1972 const cpl_table* fibers,
1973 const cxchar** names,
1974 cxint yorder, cxint worder,
1975 const GiClipParams* setup)
1978 const cxchar* center = NULL;
1986 GiPsfData* psffit = NULL;
1989 cx_assert(psfdata != NULL);
1990 cx_assert(fibers != NULL);
1991 cx_assert(names != NULL);
1992 cx_assert(setup != NULL);
1994 ns = giraffe_psfdata_fibers(psfdata);
1995 nx = giraffe_psfdata_ysize(psfdata);
1996 ny = giraffe_psfdata_xsize(psfdata);
1998 psffit = giraffe_psfdata_create(ns, nx, ny, nx);
2000 giraffe_psfdata_set_model(psffit, giraffe_psfdata_get_model(psfdata));
2009 for (i = 0; i < ns; i++) {
2011 register cxint j = 0;
2013 for (j = 0; j < nx; j++) {
2014 giraffe_psfdata_set_bin(psffit, i, j, j);
2020 if (giraffe_psfdata_contains(psfdata, center) == FALSE) {
2022 giraffe_psfdata_delete(psffit);
2030 GiPsfParameterFit pfit = {NULL, NULL};
2033 pfit.fit = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
2034 pfit.coeffs = cpl_matrix_new(yorder + 1, ns);
2036 status = _giraffe_psf_fit_profile1d(&pfit, psfdata, center, fibers,
2040 cpl_matrix_delete(pfit.coeffs);
2043 cpl_image_delete(pfit.fit);
2046 giraffe_psfdata_delete(psffit);
2052 giraffe_psfdata_set_data(psffit, center, pfit.fit);
2055 cpl_matrix_delete(pfit.coeffs);
2064 while (names[i] != NULL) {
2066 if (giraffe_psfdata_contains(psfdata, names[i]) == TRUE) {
2068 const cpl_image* xbin = giraffe_psfdata_get_bins(psfdata);
2069 const cpl_image* ybin = giraffe_psfdata_get_data(psfdata, center);
2070 const cpl_image* yfit = giraffe_psfdata_get_data(psffit, center);
2071 const cpl_image* pdata = giraffe_psfdata_get_data(psfdata,
2074 GiPsfParameterFit pfit = {NULL, NULL};
2077 pfit.fit = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
2078 pfit.coeffs = cpl_matrix_new(yorder + 1, worder + 1);
2080 status = _giraffe_psf_fit_profile2d(&pfit, fibers, pdata, xbin,
2081 ybin, yorder, worder, yfit,
2085 cpl_matrix_delete(pfit.coeffs);
2088 cpl_image_delete(pfit.fit);
2091 giraffe_psfdata_delete(psffit);
2097 giraffe_psfdata_set_data(psffit, names[i], pfit.fit);
2100 cpl_matrix_delete(pfit.coeffs);
2127 _giraffe_psf_compute_mask(GiMaskPosition* positions, GiMaskPosition* coeffs,
2128 const GiPsfData* psfdata,
const cpl_table* fibers,
2129 cxint yorder, cxint worder,
2130 const GiClipParams* setup)
2133 const cxchar*
const lcenter =
"Center";
2134 const cxchar*
const lwidth =
"Width1";
2135 const cxchar*
const lexponent =
"Width2";
2136 const cxchar* model = NULL;
2144 const cpl_image* xbin = NULL;
2145 const cpl_image* ybin = NULL;
2146 cpl_image* width = NULL;
2148 GiPsfParameterFit center = {NULL, NULL};
2149 GiPsfParameterFit halfwidth = {NULL, NULL};
2151 GiProfileId psfmodel = 0;
2154 cx_assert((positions != NULL) &&
2155 (positions->type == GIMASK_FITTED_DATA) &&
2156 (positions->my != NULL) &&
2157 (positions->mw != NULL));
2158 cx_assert((coeffs != NULL) &&
2159 (coeffs->type == GIMASK_FIT_COEFFS) &&
2160 (coeffs->my != NULL) &&
2161 (coeffs->mw != NULL));
2162 cx_assert(psfdata != NULL);
2163 cx_assert(fibers != NULL);
2164 cx_assert(setup != NULL);
2166 model = giraffe_psfdata_get_model(psfdata);
2168 if (strcmp(model,
"psfexp") == 0) {
2169 psfmodel = PROFILE_PSFEXP;
2171 else if (strcmp(model,
"psfexp2") == 0) {
2172 psfmodel = PROFILE_PSFEXP2;
2174 else if (strcmp(model,
"gaussian") == 0) {
2175 psfmodel = PROFILE_GAUSSIAN;
2181 ns = giraffe_psfdata_fibers(psfdata);
2182 nx = giraffe_psfdata_ysize(psfdata);
2183 ny = giraffe_psfdata_xsize(psfdata);
2185 if ((cpl_matrix_get_nrow(positions->my) != nx) ||
2186 (cpl_matrix_get_ncol(positions->my) != ns) ||
2187 (cpl_matrix_get_nrow(positions->mw) != nx) ||
2188 (cpl_matrix_get_ncol(positions->mw) != ns)) {
2192 if ((cpl_matrix_get_nrow(coeffs->my) != yorder + 1) ||
2193 (cpl_matrix_get_ncol(coeffs->my) != ns)) {
2197 if ((cpl_matrix_get_nrow(coeffs->mw) != worder + 1) ||
2198 (cpl_matrix_get_ncol(coeffs->mw) != worder + 1)) {
2202 if (giraffe_psfdata_contains(psfdata, lcenter) == FALSE ||
2203 giraffe_psfdata_contains(psfdata, lwidth) == FALSE) {
2207 center.fit = cpl_image_wrap_double(ns, nx,
2208 cpl_matrix_get_data(positions->my));
2209 center.coeffs = coeffs->my;
2211 status = _giraffe_psf_fit_profile1d(¢er, psfdata, lcenter, fibers,
2215 cpl_image_unwrap(center.fit);
2218 center.coeffs = NULL;
2223 width = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
2226 case PROFILE_PSFEXP:
2229 const cxdouble LOG2 = log(2.);
2231 if (giraffe_psfdata_contains(psfdata, lexponent) == FALSE) {
2232 cpl_image_delete(width);
2235 cpl_image_unwrap(center.fit);
2237 center.coeffs = NULL;
2242 for (i = 0; i < ns; i++) {
2244 register cxint j = 0;
2246 register cxdouble* _width = cpl_image_get_data_double(width);
2249 for (j = 0; j < nx; j++) {
2251 register cxint k = j * ns + i;
2254 giraffe_psfdata_get(psfdata, lwidth, i, j);
2256 giraffe_psfdata_get(psfdata, lexponent, i, j);
2259 _width[k] = 2. * pow(LOG2 * width1, 1. / width2);
2268 case PROFILE_PSFEXP2:
2271 const cxdouble LOG2 = log(2.);
2273 if (giraffe_psfdata_contains(psfdata, lexponent) == FALSE) {
2274 cpl_image_delete(width);
2277 cpl_image_unwrap(center.fit);
2279 center.coeffs = NULL;
2284 for (i = 0; i < ns; i++) {
2286 register cxint j = 0;
2288 register cxdouble* _width = cpl_image_get_data_double(width);
2291 for (j = 0; j < nx; j++) {
2293 register cxint k = j * ns + i;
2296 giraffe_psfdata_get(psfdata, lwidth, i, j);
2298 giraffe_psfdata_get(psfdata, lexponent, i, j);
2301 _width[k] = 2. * pow(LOG2, 1. / width2) * width1;
2310 case PROFILE_GAUSSIAN:
2313 const cxdouble fwhmscale = 4. * sqrt(2. * log(2.));
2315 for (i = 0; i < ns; i++) {
2317 register cxint j = 0;
2319 register cxdouble* _width = cpl_image_get_data_double(width);
2322 for (j = 0; j < nx; j++) {
2324 register cxint k = j * ns + i;
2326 _width[k] = fwhmscale *
2327 giraffe_psfdata_get(psfdata, lwidth, i, j);
2338 cpl_image_delete(width);
2341 cpl_image_unwrap(center.fit);
2343 center.coeffs = NULL;
2345 gi_error(
"Unsupported PSF profile model encountered!");
2350 xbin = giraffe_psfdata_get_bins(psfdata);
2351 ybin = giraffe_psfdata_get_data(psfdata, lcenter);
2354 halfwidth.fit = cpl_image_wrap_double(ns, nx,
2355 cpl_matrix_get_data(positions->mw));
2356 halfwidth.coeffs = coeffs->mw;
2358 status = _giraffe_psf_fit_profile2d(&halfwidth, fibers, width, xbin,
2359 ybin, worder, worder, center.fit,
2363 cpl_image_unwrap(halfwidth.fit);
2364 halfwidth.fit = NULL;
2365 halfwidth.coeffs = NULL;
2367 cpl_image_delete(width);
2370 cpl_image_unwrap(center.fit);
2372 center.coeffs = NULL;
2377 cpl_image_unwrap(halfwidth.fit);
2378 halfwidth.fit = NULL;
2379 halfwidth.coeffs = NULL;
2381 cpl_image_delete(width);
2384 cpl_image_unwrap(center.fit);
2386 center.coeffs = NULL;
2393 inline static cpl_image*
2394 _giraffe_psf_simulate_mask(
const GiPsfData* psfdata,
2395 const cpl_image* amplitude,
2396 const cpl_image* background,
2400 const cxchar* model = NULL;
2410 cxdouble bsize = 1.;
2411 cxdouble _bsize = 1.;
2412 cxdouble* _mask = NULL;
2414 const cpl_image* center = NULL;
2415 const cpl_image* width = NULL;
2416 const cpl_image* exponent = NULL;
2418 cpl_image* mask = NULL;
2420 GiModel* profile = NULL;
2422 GiProfileId psfmodel = 0;
2425 cx_assert(psfdata != NULL);
2427 model = giraffe_psfdata_get_model(psfdata);
2429 if (strcmp(model,
"psfexp") == 0) {
2430 psfmodel = PROFILE_PSFEXP;
2432 else if (strcmp(model,
"psfexp2") == 0) {
2433 psfmodel = PROFILE_PSFEXP2;
2435 else if (strcmp(model,
"gaussian") == 0) {
2436 psfmodel = PROFILE_GAUSSIAN;
2442 nfibers = giraffe_psfdata_fibers(psfdata);
2443 nbins = giraffe_psfdata_bins(psfdata);
2444 nx = giraffe_psfdata_ysize(psfdata);
2445 ny = giraffe_psfdata_xsize(psfdata);
2447 center = giraffe_psfdata_get_data(psfdata,
"Center");
2448 width = giraffe_psfdata_get_data(psfdata,
"Width1");
2449 exponent = giraffe_psfdata_get_data(psfdata,
"Width2");
2451 if (amplitude == NULL) {
2452 amplitude = giraffe_psfdata_get_data(psfdata,
"Amplitude");
2455 if ((cpl_image_get_size_x(amplitude) != nfibers) ||
2456 (cpl_image_get_size_y(amplitude) > nbins)) {
2461 if (background == NULL) {
2462 background = giraffe_psfdata_get_data(psfdata,
"Background");
2465 if ((cpl_image_get_size_x(background) != nfibers) ||
2466 (cpl_image_get_size_y(background) > nbins)) {
2471 bsize = (cxdouble)nx / (cxdouble)nbins;
2473 _nbins = cpl_image_get_size_y(amplitude);
2474 _bsize = (cxdouble)nx / (cxdouble)_nbins;
2476 mask = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
2477 _mask = cpl_image_get_data_double(mask);
2479 profile = giraffe_model_new(model);
2481 for (fiber = 0; fiber < nfibers; fiber++) {
2486 const cxdouble* _amplitude =
2487 cpl_image_get_data_double_const(amplitude);
2488 const cxdouble* _center =
2489 cpl_image_get_data_double_const(center);
2490 const cxdouble* _width =
2491 cpl_image_get_data_double_const(width);
2492 const cxdouble* _exponent =
2493 cpl_image_get_data_double_const(exponent);
2495 for (i = 0; i < nx; i++) {
2497 register cxint j = 0;
2498 register cxint k = 0;
2499 register cxint l = 0;
2500 register cxint bin = 0;
2502 register cxdouble a = 1.;
2503 register cxdouble b = 0.;
2504 register cxdouble c = 0.;
2505 register cxdouble s = 0.;
2506 register cxdouble e = 0.;
2509 bin = CX_MAX(0, CX_MIN((cxint)floor(i / bsize), nbins - 1));
2510 k = bin * nfibers + fiber;
2512 bin = CX_MAX(0, CX_MIN((cxint)floor(i / _bsize), _nbins - 1));
2513 l = bin * nfibers + fiber;
2520 giraffe_model_set_parameter(profile,
"Amplitude", a);
2521 giraffe_model_set_parameter(profile,
"Background", b);
2522 giraffe_model_set_parameter(profile,
"Center", c);
2523 giraffe_model_set_parameter(profile,
"Width1", s);
2524 giraffe_model_set_parameter(profile,
"Width2", e);
2527 case PROFILE_PSFEXP:
2529 cxdouble w = pow(s * log(1. / cutoff), 1. / e);
2531 ylower = (cxint) floor(c - w);
2532 yupper = (cxint) ceil(c + w);
2536 case PROFILE_PSFEXP2:
2538 cxdouble w = s * pow(log(1. / cutoff), 1. / e);
2540 ylower = (cxint) floor(c - w);
2541 yupper = (cxint) ceil(c + w);
2545 case PROFILE_GAUSSIAN:
2547 cxdouble w = s * sqrt(log(1. / cutoff));
2548 ylower = (cxint) floor(c - w);
2549 yupper = (cxint) ceil(c + w);
2554 gi_error(
"Unsupported PSF profile model encountered!");
2558 ylower = CX_MAX(0, ylower);
2559 yupper = CX_MIN(ny, yupper);
2561 for (j = ylower; j < yupper; j++) {
2565 cxdouble value = 0.;
2571 giraffe_model_set_argument(profile,
"x", j);
2572 giraffe_model_evaluate(profile, &value, &status);
2574 _mask[i * ny + j] += value;
2582 giraffe_model_delete(profile);
2602 GiTable* fibers, GiLocalization* master,
2603 GiImage* bpixel, GiPsfConfig* config)
2606 const cxchar*
const _func =
"giraffe_compute_fiber_profiles";
2616 cxdouble conad = 1.;
2617 cxdouble bias_ron = 0.;
2618 cxdouble bias_sigma = 0.;
2619 cxdouble dark_value = 0.;
2621 cx_string* s = NULL;
2623 cpl_table* _fibers = NULL;
2624 cpl_table* locc = NULL;
2626 cpl_matrix* my = NULL;
2628 cpl_image* _image = NULL;
2629 cpl_image* _variance = NULL;
2630 cpl_image* _locy = NULL;
2631 cpl_image* _locw = NULL;
2632 cpl_image* _bpixel = NULL;
2634 cpl_propertylist* properties = NULL;
2636 GiModel* psfmodel = NULL;
2638 GiPsfData* psfdata = NULL;
2639 GiPsfData* psffit = NULL;
2641 GiMaskPosition positions = {GIMASK_FITTED_DATA, NULL, NULL};
2642 GiMaskPosition coeffs = {GIMASK_FIT_COEFFS, NULL, NULL};
2644 GiPsfParams psf_setup = {0, 0, 1000., FALSE};
2647 if ((result == NULL) || (image == NULL) || (fibers == NULL) ||
2648 (master == NULL) || (config == NULL)) {
2649 cpl_error_set(_func, CPL_ERROR_NULL_INPUT);
2653 if ((master->locy == NULL) || (master->locw == NULL)) {
2654 cpl_error_set(_func, CPL_ERROR_NULL_INPUT);
2658 if ((result->locy != NULL) || (result->locw != NULL) ||
2659 (result->locc != NULL) || (result->psf != NULL)) {
2660 cpl_error_set(_func, CPL_ERROR_ILLEGAL_INPUT);
2668 if (bpixel != NULL) {
2674 if (_fibers == NULL) {
2675 cpl_error_set(_func, CPL_ERROR_DATA_NOT_FOUND);
2679 nfibers = cpl_table_get_nrow(_fibers);
2681 nx = cpl_image_get_size_y(_image);
2682 ny = cpl_image_get_size_x(_image);
2684 nbins = (cxint) ceil(nx / config->binsize);
2693 if (cpl_propertylist_has(properties, GIALIAS_NFIBERS) == FALSE) {
2694 cpl_propertylist_append_int(properties, GIALIAS_NFIBERS, nfibers);
2695 cpl_propertylist_set_comment(properties, GIALIAS_NFIBERS,
2696 "Number of fibres");
2700 cxint _nfibers = cpl_propertylist_get_int(properties,
2703 if (nfibers != _nfibers) {
2704 cpl_error_set(_func, CPL_ERROR_ILLEGAL_INPUT);
2711 giraffe_error_push();
2715 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2719 giraffe_error_pop();
2722 if (!cpl_propertylist_has(properties, GIALIAS_BIASERROR)) {
2723 cpl_msg_warning(_func,
"Missing bias error property (%s)! Setting "
2724 "bias error to 0.", GIALIAS_BIASERROR);
2728 bias_sigma = cpl_propertylist_get_double(properties, GIALIAS_BIASERROR);
2732 giraffe_error_push();
2736 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2740 giraffe_error_pop();
2743 if (cpl_propertylist_has(properties, GIALIAS_DARKVALUE) == FALSE) {
2744 cpl_msg_warning(_func,
"Missing dark value property (%s) will be "
2745 "set to %.2f!", GIALIAS_DARKVALUE, dark_value);
2746 cpl_propertylist_append_double(properties, GIALIAS_DARKVALUE,
2750 dark_value = cpl_propertylist_get_double(properties,
2755 if (cpl_propertylist_has(properties, GIALIAS_DATANCOM)) {
2756 nframes = cpl_propertylist_get_int(properties, GIALIAS_DATANCOM);
2764 bias_sigma *= conad;
2765 dark_value *= conad;
2772 giraffe_error_push();
2774 _image = cpl_image_multiply_scalar_create(_image, nframes * conad);
2775 _variance = cpl_image_abs_create(_image);
2777 cpl_image_add_scalar(_variance,
2778 nframes * (bias_ron * bias_ron + nframes *
2779 (bias_sigma * bias_sigma + dark_value * dark_value)));
2781 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2782 if (_variance != NULL) {
2783 cpl_image_delete(_variance);
2787 cpl_image_delete(_image);
2793 giraffe_error_pop();
2800 psfmodel = giraffe_model_new(config->profile);
2802 giraffe_model_thaw(psfmodel);
2804 giraffe_model_set_parameter(psfmodel,
"Amplitude", 1.);
2805 giraffe_model_set_parameter(psfmodel,
"Background", 0.);
2806 giraffe_model_set_parameter(psfmodel,
"Center", 0.);
2807 giraffe_model_set_parameter(psfmodel,
"Width1", config->width);
2809 if (cx_strncasecmp(config->profile,
"psfexp", 6) == 0) {
2811 cxdouble _exponent = fabs(config->exponent);
2813 giraffe_model_set_parameter(psfmodel,
"Width2", _exponent);
2815 if (config->exponent > 0) {
2816 giraffe_model_freeze_parameter(psfmodel,
"Width2");
2821 giraffe_model_set_iterations(psfmodel, config->fit.iterations);
2822 giraffe_model_set_delta(psfmodel, config->fit.delta);
2823 giraffe_model_set_tests(psfmodel, config->fit.tests);
2831 cpl_msg_info(_func,
"Fitting fiber profiles ...");
2833 psf_setup.bsize = config->binsize;
2834 psf_setup.mwidth = config->maxwidth;
2835 psf_setup.normalize = config->normalize;
2837 psfdata = giraffe_psfdata_create(nfibers, nbins, ny, nx);
2839 status = _giraffe_psf_compute_profile(psfdata, _image, _variance, _locy,
2840 _locw, _fibers, _bpixel, psfmodel,
2843 cpl_image_delete(_image);
2847 giraffe_psfdata_delete(psfdata);
2850 giraffe_model_delete(psfmodel);
2853 cpl_image_delete(_variance);
2856 cpl_msg_error(_func,
"Fiber profile fit failed!");
2867 _image = (cpl_image*) giraffe_psfdata_get_data(psfdata,
"Amplitude");
2868 cpl_image_divide_scalar(_image, nframes * conad);
2870 _image = (cpl_image*) giraffe_psfdata_get_data(psfdata,
"Background");
2871 cpl_image_divide_scalar(_image, nframes * conad);
2881 cpl_msg_info(_func,
"Fitting PSF profile parameters ...");
2883 if (config->parameter_fit == TRUE) {
2885 const cxchar* parameters[] = {
"Center",
"Amplitude",
"Background",
2886 "Width1",
"Width2", NULL};
2888 psffit = _giraffe_psf_fit_parameters(psfdata, _fibers, parameters,
2889 config->yorder, config->worder,
2895 psffit = _giraffe_psf_fit_parameters1d(psfdata, _fibers,
2896 NULL, config->yorder,
2901 if (psffit == NULL) {
2902 giraffe_psfdata_delete(psfdata);
2905 giraffe_model_delete(psfmodel);
2908 cpl_image_delete(_variance);
2911 cpl_msg_error(_func,
"PSF parameter fit failed!");
2915 giraffe_model_delete(psfmodel);
2918 cpl_image_delete(_variance);
2926 positions.my = cpl_matrix_new(nx, nfibers);
2927 positions.mw = cpl_matrix_new(nx, nfibers);
2929 coeffs.my = cpl_matrix_new(config->yorder + 1, nfibers);
2930 coeffs.mw = cpl_matrix_new(config->worder + 1, config->worder + 1);
2932 status = _giraffe_psf_compute_mask(&positions, &coeffs, psfdata, _fibers,
2933 config->yorder, config->worder,
2938 giraffe_psfdata_delete(psffit);
2941 giraffe_psfdata_delete(psfdata);
2944 cpl_msg_error(_func,
"Computation of localization mask from "
2945 "the fiber profile failed!");
2950 giraffe_psfdata_delete(psfdata);
2961 cpl_propertylist_update_string(properties, GIALIAS_PSFMODEL,
2963 cpl_propertylist_set_comment(properties, GIALIAS_PSFMODEL,
2964 "PSF profile model identifier");
2966 cpl_propertylist_update_int(properties, GIALIAS_PSFXBINS,
2968 cpl_propertylist_set_comment(properties, GIALIAS_PSFXBINS,
2969 "Size of bins along the dispersion "
2972 cpl_propertylist_update_int(properties, GIALIAS_PSFYDEG,
2974 cpl_propertylist_set_comment(properties, GIALIAS_PSFYDEG,
2975 "Order of the fiber center polynomial "
2978 cpl_propertylist_update_int(properties, GIALIAS_PSFWDEG,
2980 cpl_propertylist_set_comment(properties, GIALIAS_PSFWDEG,
2981 "Order of the fiber width 2d polynomial "
2984 cpl_propertylist_update_int(properties, GIALIAS_PSFWDEG,
2986 cpl_propertylist_set_comment(properties, GIALIAS_PSFWDEG,
2987 "Order of the fiber width 2d polynomial "
2990 cpl_propertylist_update_bool(properties, GIALIAS_PSFNORM,
2992 cpl_propertylist_set_comment(properties, GIALIAS_PSFNORM,
2993 "Pixel value normalization.");
2995 cpl_propertylist_update_int(properties, GIALIAS_PSFNX,
2996 cpl_matrix_get_nrow(positions.my));
2997 cpl_propertylist_set_comment(properties, GIALIAS_PSFNX,
2998 "Number of pixels per spectrum.");
3000 cpl_propertylist_update_int(properties, GIALIAS_PSFNS,
3001 cpl_matrix_get_ncol(positions.my));
3002 cpl_propertylist_set_comment(properties, GIALIAS_PSFNS,
3003 "Number of detected fibers.");
3005 cpl_propertylist_update_double(properties, GIALIAS_PSFSIGMA,
3006 config->clip.level);
3007 cpl_propertylist_set_comment(properties, GIALIAS_PSFSIGMA,
3008 "Sigma multiplier used for the PSF "
3011 cpl_propertylist_update_double(properties, GIALIAS_PSFSIGMA,
3012 config->clip.level);
3013 cpl_propertylist_set_comment(properties, GIALIAS_PSFSIGMA,
3014 "Sigma multiplier used for the fit of PSF "
3017 cpl_propertylist_update_int(properties, GIALIAS_PSFNITER,
3018 config->clip.iterations);
3019 cpl_propertylist_set_comment(properties, GIALIAS_PSFNITER,
3020 "Number of iterations used for the fit "
3021 "of PSF parameters.");
3023 cpl_propertylist_update_double(properties, GIALIAS_PSFMFRAC,
3024 config->clip.fraction);
3025 cpl_propertylist_set_comment(properties, GIALIAS_PSFMFRAC,
3026 "Minimum allowed fraction of accepted "
3027 "over total data points used for the "
3028 "fit of PSF parameters.");
3034 cpl_matrix_get_ncol(positions.my),
3035 cpl_matrix_get_nrow(positions.my));
3038 cpl_matrix_delete(positions.my);
3039 positions.my = NULL;
3044 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
"LOCY");
3045 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
3046 "GIRAFFE localization centroid");
3052 cpl_matrix_get_ncol(positions.mw),
3053 cpl_matrix_get_nrow(positions.mw));
3056 cpl_matrix_delete(positions.mw);
3057 positions.mw = NULL;
3064 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
"LOCWY");
3065 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
3066 "GIRAFFE localization half-width");
3071 locc = cpl_table_new(cpl_matrix_get_ncol(coeffs.my));
3073 cpl_table_new_column(locc,
"BUTTON", CPL_TYPE_INT);
3074 for (i = 0; i < cpl_table_get_nrow(locc); i++) {
3075 cpl_table_set_int(locc,
"BUTTON", i, i);
3078 for (i = 0; i < cpl_matrix_get_nrow(coeffs.my); i++) {
3080 cxchar* label = NULL;
3082 cx_asprintf(&label,
"YC%d", i);
3083 cpl_table_new_column(locc, label, CPL_TYPE_DOUBLE);
3093 cpl_table_delete(locc);
3096 my = cpl_matrix_transpose_create(coeffs.my);
3099 cpl_matrix_delete(my);
3102 cpl_matrix_delete(coeffs.my);
3108 s = cx_string_new();
3110 for (i = 0; i < cpl_matrix_get_ncol(coeffs.mw); i++) {
3111 cx_string_sprintf(s,
"%s%d", GIALIAS_LOCWIDCOEF, i);
3112 cpl_propertylist_update_double(properties, cx_string_get(s),
3113 cpl_matrix_get(coeffs.mw, 0, i));
3116 cx_string_delete(s);
3119 cpl_matrix_delete(coeffs.mw);
3122 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
3124 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
3125 "GIRAFFE localization fit coefficients");
3130 if (psffit != NULL) {
3131 result->psf = psffit;
3155 GiPsfConfig *
self = NULL;
3162 self = cx_calloc(1,
sizeof *
self);
3164 p = cpl_parameterlist_find(list,
"giraffe.psf.model");
3165 self->profile = cx_strdup(cpl_parameter_get_string(p));
3167 if (cx_strncasecmp(self->profile,
"psfexp", 6) == 0) {
3174 p = cpl_parameterlist_find(list,
"giraffe.psf.binsize");
3175 self->binsize = cpl_parameter_get_int(p);
3177 if (self->binsize < 1) {
3181 p = cpl_parameterlist_find(list,
"giraffe.psf.maxwidth");
3182 self->maxwidth = cpl_parameter_get_double(p);
3184 if (self->width > 0.) {
3185 p = cpl_parameterlist_find(list,
"giraffe.psf.width");
3186 self->width = cpl_parameter_get_double(p);
3189 if (self->width > self->maxwidth) {
3190 self->width =
self->maxwidth;
3193 p = cpl_parameterlist_find(list,
"giraffe.psf.exponent");
3194 self->exponent = cpl_parameter_get_double(p);
3196 p = cpl_parameterlist_find(list,
"giraffe.psf.normalize");
3197 self->normalize = cpl_parameter_get_bool(p);
3199 p = cpl_parameterlist_find(list,
"giraffe.psf.profile.iterations");
3200 self->fit.iterations = cpl_parameter_get_int(p);
3202 p = cpl_parameterlist_find(list,
"giraffe.psf.profile.tests");
3203 self->fit.tests = cpl_parameter_get_int(p);
3205 p = cpl_parameterlist_find(list,
"giraffe.psf.profile.dchisquare");
3206 self->fit.delta = cpl_parameter_get_double(p);
3208 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.fit");
3209 self->parameter_fit = cpl_parameter_get_bool(p);
3211 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.yorder");
3212 self->yorder = cpl_parameter_get_int(p);
3214 if (self->yorder < 0) {
3219 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.worder");
3220 self->worder = cpl_parameter_get_int(p);
3222 if (self->worder < 0) {
3227 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.sigma");
3228 self->clip.level = cpl_parameter_get_double(p);
3230 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.iterations");
3231 self->clip.iterations = cpl_parameter_get_int(p);
3233 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.fraction");
3234 self->clip.fraction = cpl_parameter_get_double(p);
3258 if (self->profile != NULL) {
3259 cx_free((cxptr) self->profile);
3260 self->profile = NULL;
3286 cpl_parameter* p = NULL;
3293 p = cpl_parameter_new_enum(
"giraffe.psf.model",
3295 "PSF profile model: `psfexp', `psfexp2'",
3297 "psfexp2", 3,
"psfexp",
"psfexp2",
"gaussian");
3298 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-model");
3299 cpl_parameterlist_append(list, p);
3301 p = cpl_parameter_new_value(
"giraffe.psf.normalize",
3303 "Use normalized pixel values.",
3306 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-norm");
3307 cpl_parameterlist_append(list, p);
3310 p = cpl_parameter_new_value(
"giraffe.psf.binsize",
3312 "Size of bin along dispersion axis",
3315 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-binsize");
3316 cpl_parameterlist_append(list, p);
3319 p = cpl_parameter_new_value(
"giraffe.psf.maxwidth",
3321 "Maximum width of the PSF profile.",
3324 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-maxwidth");
3325 cpl_parameterlist_append(list, p);
3328 p = cpl_parameter_new_value(
"giraffe.psf.width",
3330 "Initial width of the PSF profile.",
3333 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-width");
3334 cpl_parameterlist_append(list, p);
3337 p = cpl_parameter_new_value(
"giraffe.psf.exponent",
3339 "Exponent of the exponential PSF profile "
3340 "(will not be fitted if > 0).",
3343 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-exponent");
3344 cpl_parameterlist_append(list, p);
3347 p = cpl_parameter_new_value(
"giraffe.psf.profile.iterations",
3349 "Maximum number of iterations used for "
3350 "the fit of the fiber PSF profile.",
3354 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-pfniter");
3355 cpl_parameterlist_append(list, p);
3358 p = cpl_parameter_new_value(
"giraffe.psf.profile.tests",
3360 "Maximum number of tests used for the fit "
3361 "of the fiber PSF profile",
3365 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-pfntest");
3366 cpl_parameterlist_append(list, p);
3369 p = cpl_parameter_new_value(
"giraffe.psf.profile.dchisquare",
3371 "Minimum chi-square difference used for the "
3372 "fit of the fiber PSF profile.",
3376 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-pfdchisq");
3377 cpl_parameterlist_append(list, p);
3380 p = cpl_parameter_new_value(
"giraffe.psf.parameters.fit",
3382 "2D fit of the PSF profile parameters "
3383 "using a Chebyshev polynomial model.",
3386 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-prmfit");
3387 cpl_parameterlist_append(list, p);
3390 p = cpl_parameter_new_value(
"giraffe.psf.parameters.yorder",
3392 "Order of Chebyshev polynomial fit.",
3395 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-yorder");
3396 cpl_parameterlist_append(list, p);
3399 p = cpl_parameter_new_value(
"giraffe.psf.parameters.worder",
3401 "Order of Chebyshev 2D polynomial fit.",
3404 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-worder");
3405 cpl_parameterlist_append(list, p);
3408 p = cpl_parameter_new_value(
"giraffe.psf.parameters.sigma",
3410 "PSF parameter fitting: sigma threshold "
3414 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-sigma");
3415 cpl_parameterlist_append(list, p);
3418 p = cpl_parameter_new_value(
"giraffe.psf.parameters.iterations",
3420 "PSF parameter fitting: number of "
3424 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-niter");
3425 cpl_parameterlist_append(list, p);
3428 p = cpl_parameter_new_range(
"giraffe.psf.parameters.fraction",
3430 "PSF parameter fitting: minimum fraction "
3431 "of points accepted/total.",
3434 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-mfrac");
3435 cpl_parameterlist_append(list, p);
const cxchar * giraffe_fiberlist_query_index(const cpl_table *fibers)
Query a fiber list for the name of the fiber reference index column.
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
cxint giraffe_image_copy_matrix(GiImage *self, cpl_matrix *matrix)
Copies matrix elements into an image.
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
GiImage * giraffe_image_create(cpl_type type, cxint nx, cxint ny)
Creates an image container of a given type.
cxint giraffe_image_set_properties(GiImage *self, cpl_propertylist *properties)
Attaches a property list to an image.
cpl_matrix * giraffe_matrix_leastsq(const cpl_matrix *mA, const cpl_matrix *mB)
Computes the solution of an equation using a pseudo-inverse.
cxdouble giraffe_matrix_sigma_mean(const cpl_matrix *matrix, cxdouble mean)
Compute sigma of matrix elements, with a given mean value.
void gi_error(const cxchar *format,...)
Log an error message.
void giraffe_psf_config_destroy(GiPsfConfig *self)
Destroys a PSF profile fit setup object.
GiPsfConfig * giraffe_psf_config_create(cpl_parameterlist *list)
Creates a setup object for the PSF profile fit.
cxint giraffe_compute_fiber_profiles(GiLocalization *result, GiImage *image, GiTable *fibers, GiLocalization *master, GiImage *bpixel, GiPsfConfig *config)
Compute the position and width of the spectra from the fiber profile.
void giraffe_psf_config_add(cpl_parameterlist *list)
Adds parameters for the PSF profile computation of the fibers.
cxint giraffe_table_copy_matrix(GiTable *table, const cxchar *name, cpl_matrix *matrix)
Copies matrix elements into a table.
GiTable * giraffe_table_create(cpl_table *table, cpl_propertylist *properties)
Creates a Giraffe table from a table and a property list.
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
cxdouble giraffe_propertylist_get_conad(const cpl_propertylist *properties)
Retrieve the ADU to electrons conversion factor from the given properties.
cxdouble giraffe_propertylist_get_ron(const cpl_propertylist *properties)
Retrieve the read-out noise from the given properties.