29#include <cxmessages.h>
31#include <cxstrutils.h>
36#include <cpl_parameterlist.h>
41#include "gimessages.h"
43#include "gichebyshev.h"
46#include "gilocalization.h"
50#include "gifiberutils.h"
63 PROFILE_PSFEXP = 1 << 1,
64 PROFILE_PSFEXP2 = 1 << 2,
65 PROFILE_GAUSSIAN = 1 << 3
68typedef enum GiProfileId GiProfileId;
78typedef struct GiPsfParams GiPsfParams;
89typedef struct GiPsfBin GiPsfBin;
91struct GiPsfParameterFit {
96typedef 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);
859 cpl_matrix* mx = NULL;
860 cpl_matrix* my = NULL;
861 cpl_matrix* ms = NULL;
863 cpl_image* zx = NULL;
864 cpl_image* zv = NULL;
866 GiProfileId psfmodel = 0;
869 cx_assert(result != NULL);
870 cx_assert((zraw != NULL) && (zvar != NULL));
871 cx_assert((locy != NULL) && (locw != NULL));
872 cx_assert(fibers != NULL);
873 cx_assert(profile != NULL);
874 cx_assert(config != NULL);
876 cx_assert(cpl_image_get_size_x(zraw) == cpl_image_get_size_x(zvar));
877 cx_assert(cpl_image_get_size_y(zraw) == cpl_image_get_size_y(zvar));
879 cx_assert(cpl_image_get_size_x(locy) == cpl_image_get_size_x(locw));
880 cx_assert(cpl_image_get_size_y(locy) == cpl_image_get_size_y(locw));
883 nx = cpl_image_get_size_y(zraw);
884 ny = cpl_image_get_size_x(zraw);
885 ns = cpl_table_get_nrow(fibers);
887 nbins = (cxint) giraffe_psfdata_bins(result);
889 if (ns != cpl_image_get_size_x(locy)) {
893 if ((bpm != NULL) && (cpl_image_get_type(bpm) != CPL_TYPE_INT)) {
897 if (giraffe_psfdata_fibers(result) != (cxsize) ns) {
901 if ((giraffe_psfdata_xsize(result) != (cxsize) ny) ||
902 (giraffe_psfdata_ysize(result) != (cxsize) nx)) {
912 model = giraffe_model_get_name(profile);
914 if (strcmp(model,
"psfexp") == 0) {
915 psfmodel = PROFILE_PSFEXP;
917 else if (strcmp(model,
"psfexp2") == 0) {
918 psfmodel = PROFILE_PSFEXP2;
920 else if (strcmp(model,
"gaussian") == 0) {
921 psfmodel = PROFILE_GAUSSIAN;
928 if (config->normalize != FALSE) {
933 cxdouble* zsum = cx_calloc(nx,
sizeof(cxdouble));
943 for (x = 0; x < nx; x++) {
945 register cxint y = 0;
947 register const cxdouble* _zraw =
948 cpl_image_get_data_double(zraw);
951 for (y = 0; y < ny; y++) {
952 zsum[x] += _zraw[x * ny + y];
955 if (zsum[x] > zmax) {
963 for (x = 0; x < nx; x++) {
965 register cxint y = 0;
966 register const cxint* _bpm = cpl_image_get_data_int(bpm);
968 register const cxdouble* _zraw =
969 cpl_image_get_data_double(zraw);
972 for (y = 0; y < ny; y++) {
973 register cxint i = x * ny + y;
980 if (zsum[x] > zmax) {
993 zx = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
994 zv = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
997 for (x = 0; x < nx; x++) {
999 register cxint y = 0;
1001 register cxdouble scale = zmax / zsum[x];
1002 register const cxdouble* _zraw = cpl_image_get_data_double(zraw);
1003 register const cxdouble* _zvar = cpl_image_get_data_double(zvar);
1004 register cxdouble* _zx = cpl_image_get_data_double(zx);
1005 register cxdouble* _zv = cpl_image_get_data_double(zv);
1007 for(y = 0; y < nx; y++) {
1008 register cxint i = x * ny + y;
1010 _zx[i] = _zraw[i] * scale;
1011 _zv[i] = _zvar[i] * scale;
1031 giraffe_error_push();
1033 exponent = giraffe_model_get_parameter(profile,
"Width2");
1035 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1039 giraffe_error_pop();
1056 mx = cpl_matrix_new(nbins * config->mwidth, 1);
1057 my = cpl_matrix_new(nbins * config->mwidth, 1);
1058 ms = cpl_matrix_new(nbins * config->mwidth, 1);
1060 if ((mx == NULL) || (my == NULL) || (ms == NULL)) {
1061 if (config->normalize == TRUE) {
1062 cpl_image_delete(zx);
1065 cpl_image_delete(zv);
1070 cpl_matrix_delete(mx);
1075 cpl_matrix_delete(my);
1080 cpl_matrix_delete(ms);
1093 giraffe_psfdata_set_model(result, giraffe_model_get_name(profile));
1095 for (n = 0; n < giraffe_model_count_parameters(profile); n++) {
1097 const cxchar* name = giraffe_model_parameter_name(profile, n);
1099 cpl_image* values = cpl_image_new(ns, nbins, CPL_TYPE_DOUBLE);
1101 if ((name == NULL) || (values == NULL)) {
1103 giraffe_psfdata_clear(result);
1105 cpl_matrix_delete(mx);
1108 cpl_matrix_delete(my);
1111 cpl_matrix_delete(ms);
1114 if (config->normalize == TRUE) {
1115 cpl_image_delete(zx);
1118 cpl_image_delete(zv);
1125 giraffe_psfdata_set_data(result, name, values);
1134 for (fiber = 0; fiber < ns; fiber++) {
1138 cxint cs = cpl_table_get_int(fibers, ridx, fiber, NULL) - 1;
1139 const cxint* _bpm = NULL;
1141 const cxdouble* _locy = cpl_image_get_data_double(locy);
1142 const cxdouble* _locw = cpl_image_get_data_double(locw);
1143 const cxdouble* _zx = cpl_image_get_data_double(zx);
1144 const cxdouble* _zv = cpl_image_get_data_double(zv);
1148 _bpm = cpl_image_get_data_int(bpm);
1156 for (x = 0, bin = 0; x < nx; x += config->bsize, bin++) {
1158 register cxint k = 0;
1159 register cxint xx = 0;
1163 cxint iterations = giraffe_model_get_iterations(profile);
1165 cxdouble amplitude = 0.;
1166 cxdouble bckground = 0.;
1167 cxdouble center = 0.;
1168 cxdouble width1 = 0.;
1169 cxdouble width2 = 0.;
1171 GiPsfBin xbin = {0., 0., 0., 0., 0.};
1178 for (k = 0, xx = x; (k < config->bsize) && (xx < nx); k++, xx++) {
1180 register cxint y = 0;
1181 register cxint l = xx * ns + cs;
1182 register cxint m = xx * ny;
1184 cxdouble zxmin = CX_MAXDOUBLE;
1185 cxdouble zxmax = 0.;
1186 cxdouble swidth = CX_MIN(_locw[l], config->mwidth);
1187 cxdouble ylo = (cxint) floor(_locy[l] - swidth);
1188 cxdouble yup = (cxint) ceil(_locy[l] + swidth);
1189 cxdouble ycenter = _locy[l];
1192 ylo = CX_MAX(0., ylo);
1193 yup = CX_MIN(ny, yup);
1197 for (y = ylo; y < yup; y++) {
1199 register cxint i = m + y;
1201 cpl_matrix_set(mx, ndata, 0, (cxdouble)y - ycenter);
1202 cpl_matrix_set(my, ndata, 0, _zx[i]);
1203 cpl_matrix_set(ms, ndata, 0, sqrt(_zv[i]));
1205 if (_zx[i] > zxmax) {
1209 if (_zx[i] < zxmin) {
1220 for (y = ylo; y < yup; y++) {
1222 register cxint i = m + y;
1225 cpl_matrix_set(mx, ndata, 0,
1226 (cxdouble)y - ycenter);
1227 cpl_matrix_set(my, ndata, 0, _zx[i]);
1228 cpl_matrix_set(ms, ndata, 0, sqrt(_zv[i]));
1230 if (_zx[i] > zxmax) {
1234 if (_zx[i] < zxmin) {
1248 xbin.ycenter += ycenter;
1249 xbin.ywidth += swidth;
1269 xbin.zmin = CX_MAX(0., xbin.zmin);
1276 giraffe_model_set_parameter(profile,
"Amplitude",
1277 xbin.zmax - xbin.zmin);
1278 giraffe_model_set_parameter(profile,
"Center", 0.);
1279 giraffe_model_set_parameter(profile,
"Background", xbin.zmin);
1282 case PROFILE_PSFEXP:
1283 width1 = pow(xbin.ywidth, exponent) / cutoff;
1284 giraffe_model_set_parameter(profile,
"Width2", exponent);
1287 case PROFILE_PSFEXP2:
1288 width1 = xbin.ywidth / pow(cutoff, 1. / exponent);
1289 giraffe_model_set_parameter(profile,
"Width2", exponent);
1292 case PROFILE_GAUSSIAN:
1293 width1 = xbin.ywidth / pow(cutoff, 0.5);
1300 giraffe_model_set_parameter(profile,
"Width1", width1);
1307 status = giraffe_model_fit_sequence(profile, mx, my, ms,
1310 amplitude = giraffe_model_get_parameter(profile,
"Amplitude");
1311 bckground = giraffe_model_get_parameter(profile,
"Background");
1312 center = giraffe_model_get_parameter(profile,
"Center");
1313 width1 = giraffe_model_get_parameter(profile,
"Width1");
1315 if ((psfmodel == PROFILE_PSFEXP) ||
1316 (psfmodel == PROFILE_PSFEXP2)) {
1317 width2 = giraffe_model_get_parameter(profile,
"Width2");
1326 if ((status != 0) ||
1327 (giraffe_model_get_position(profile) >= iterations) ||
1328 (amplitude <= 0.) ||
1340 giraffe_psfdata_set_bin(result, fiber, bin, xbin.xcenter);
1342 giraffe_psfdata_set(result,
"Amplitude", fiber, bin, amplitude);
1343 giraffe_psfdata_set(result,
"Center", fiber, bin,
1344 xbin.ycenter + center);
1345 giraffe_psfdata_set(result,
"Background", fiber, bin, bckground);
1346 giraffe_psfdata_set(result,
"Width1", fiber, bin, width1);
1348 if ((psfmodel == PROFILE_PSFEXP) ||
1349 (psfmodel == PROFILE_PSFEXP2)) {
1350 giraffe_psfdata_set(result,
"Width2", fiber, bin, width2);
1362 cpl_matrix_delete(mx);
1365 cpl_matrix_delete(my);
1368 cpl_matrix_delete(ms);
1371 if (config->normalize == TRUE) {
1372 cpl_image_delete(zx);
1375 cpl_image_delete(zv);
1411_giraffe_psf_refine_profile(GiPsfData* result,
const GiPsfData* psfdata,
1412 cpl_image* zraw, cpl_image* zvar,
1413 cpl_table* fibers, cpl_image* bpm,
1414 GiModel* profile, GiPsfParams* config)
1417 const cxchar* model = NULL;
1419 const cxdouble cutoff = log(config->limit);
1431 cpl_matrix* mx = NULL;
1432 cpl_matrix* my = NULL;
1433 cpl_matrix* ms = NULL;
1435 GiProfileId psfmodel = 0;
1438 cx_assert(result != NULL);
1439 cx_assert(psfdata != NULL);
1440 cx_assert((zraw != NULL) && (zvar != NULL));
1441 cx_assert(fibers != NULL);
1442 cx_assert(profile != NULL);
1443 cx_assert(config != NULL);
1445 cx_assert(cpl_image_get_size_x(zraw) == cpl_image_get_size_x(zvar));
1446 cx_assert(cpl_image_get_size_y(zraw) == cpl_image_get_size_y(zvar));
1449 nx = cpl_image_get_size_y(zraw);
1450 ny = cpl_image_get_size_x(zraw);
1451 ns = cpl_table_get_nrow(fibers);
1453 if ((bpm != NULL) && (cpl_image_get_type(bpm) != CPL_TYPE_INT)) {
1457 if ((giraffe_psfdata_fibers(result) != (cxsize) ns) ||
1458 (giraffe_psfdata_bins(result) != (cxsize) nx)) {
1462 if ((giraffe_psfdata_xsize(result) != (cxsize) ny) ||
1463 (giraffe_psfdata_ysize(result) != (cxsize) nx)) {
1467 nbins = giraffe_psfdata_bins(result);
1469 if ((giraffe_psfdata_fibers(psfdata) != (cxsize) ns)) {
1473 if ((giraffe_psfdata_xsize(psfdata) != (cxsize) ny) ||
1474 (giraffe_psfdata_ysize(psfdata) != (cxsize) nx)) {
1478 binsize = nx / giraffe_psfdata_bins(psfdata);
1486 model = giraffe_model_get_name(profile);
1488 if (strcmp(model,
"psfexp") == 0) {
1489 psfmodel = PROFILE_PSFEXP;
1491 else if (strcmp(model,
"psfexp2") == 0) {
1492 psfmodel = PROFILE_PSFEXP2;
1494 else if (strcmp(model,
"gaussian") == 0) {
1495 psfmodel = PROFILE_GAUSSIAN;
1508 mx = cpl_matrix_new(nbins * config->mwidth, 1);
1509 my = cpl_matrix_new(nbins * config->mwidth, 1);
1510 ms = cpl_matrix_new(nbins * config->mwidth, 1);
1512 if ((mx == NULL) || (my == NULL) || (ms == NULL)) {
1515 cpl_matrix_delete(mx);
1520 cpl_matrix_delete(my);
1525 cpl_matrix_delete(ms);
1539 giraffe_psfdata_set_model(result, giraffe_model_get_name(profile));
1541 for (n = 0; n < giraffe_model_count_parameters(profile); n++) {
1543 const cxchar* name = giraffe_model_parameter_name(profile, n);
1545 cpl_image* values = cpl_image_new(ns, nbins, CPL_TYPE_DOUBLE);
1548 if ((name == NULL) || (values == NULL)) {
1550 giraffe_psfdata_clear(result);
1552 cpl_matrix_delete(mx);
1555 cpl_matrix_delete(my);
1558 cpl_matrix_delete(ms);
1565 giraffe_psfdata_set_data(result, name, values);
1574 for (fiber = 0; fiber < ns; fiber++) {
1577 const cxint* _bpm = NULL;
1579 const cxdouble* _zx = cpl_image_get_data_double(zraw);
1580 const cxdouble* _zv = cpl_image_get_data_double(zvar);
1584 _bpm = cpl_image_get_data_int(bpm);
1592 for (x = 0; x < nx; x++) {
1594 register cxint y = 0;
1595 register cxint m = x * ny;
1596 register cxint bin = CX_MAX(0, CX_MIN((cxint) floor(x / binsize),
1601 cxint iterations = giraffe_model_get_iterations(profile);
1603 cxdouble xcenter = 0.;
1604 cxdouble ycenter = 0.;
1605 cxdouble swidth = 0.;
1608 cxdouble amplitude = giraffe_psfdata_get(psfdata,
"Amplitude",
1610 cxdouble bckground = giraffe_psfdata_get(psfdata,
"Background",
1612 cxdouble center = giraffe_psfdata_get(psfdata,
"Center",
1614 cxdouble width1 = giraffe_psfdata_get(psfdata,
"Width1",
1616 cxdouble width2 = 0.;
1620 case PROFILE_PSFEXP:
1621 width2 = giraffe_psfdata_get(psfdata,
"Width2",
1623 swidth = pow(width1 * cutoff, 1./ width2);
1626 case PROFILE_PSFEXP2:
1627 width2 = giraffe_psfdata_get(psfdata,
"Width2",
1629 swidth = width1 * pow(cutoff, 1./ width2);
1632 case PROFILE_GAUSSIAN:
1633 swidth = width1 * pow(cutoff, 0.5);
1640 swidth = CX_MIN(swidth, config->mwidth);
1642 ylo = (cxint) floor(center - swidth);
1643 ylo = CX_MAX(0., ylo);
1645 yup = (cxint) ceil(center + swidth);
1646 yup = CX_MIN(ny, yup);
1650 for (y = ylo; y < yup; y++) {
1652 register cxint i = m + y;
1654 cpl_matrix_set(mx, ndata, 0, (cxdouble)y - center);
1655 cpl_matrix_set(my, ndata, 0, _zx[i]);
1656 cpl_matrix_set(ms, ndata, 0, sqrt(_zv[i]));
1665 for (y = ylo; y < yup; y++) {
1667 register cxint i = m + y;
1670 cpl_matrix_set(mx, ndata, 0, (cxdouble)y - center);
1671 cpl_matrix_set(my, ndata, 0, _zx[i]);
1672 cpl_matrix_set(ms, ndata, 0, sqrt(_zv[i]));
1686 bckground = CX_MAX(0., bckground);
1693 giraffe_model_set_parameter(profile,
"Amplitude", amplitude);
1694 giraffe_model_set_parameter(profile,
"Center", 0.);
1695 giraffe_model_set_parameter(profile,
"Background", bckground);
1696 giraffe_model_set_parameter(profile,
"Width1", width1);
1699 case PROFILE_PSFEXP:
1700 giraffe_model_set_parameter(profile,
"Width2", width2);
1703 case PROFILE_PSFEXP2:
1704 giraffe_model_set_parameter(profile,
"Width2", width2);
1707 case PROFILE_GAUSSIAN:
1719 status = giraffe_model_fit_sequence(profile, mx, my, ms,
1722 amplitude = giraffe_model_get_parameter(profile,
"Amplitude");
1723 bckground = giraffe_model_get_parameter(profile,
"Background");
1724 ycenter = giraffe_model_get_parameter(profile,
"Center");
1725 width1 = giraffe_model_get_parameter(profile,
"Width1");
1727 if ((psfmodel == PROFILE_PSFEXP) ||
1728 (psfmodel == PROFILE_PSFEXP2)) {
1729 width2 = giraffe_model_get_parameter(profile,
"Width2");
1739 if ((status != 0) ||
1740 (giraffe_model_get_position(profile) >= iterations) ||
1741 (amplitude <= 0.) ||
1756 giraffe_psfdata_set_bin(result, fiber, x, xcenter);
1758 giraffe_psfdata_set(result,
"Amplitude", fiber, x, amplitude);
1759 giraffe_psfdata_set(result,
"Center", fiber, x,
1761 giraffe_psfdata_set(result,
"Background", fiber, x, bckground);
1762 giraffe_psfdata_set(result,
"Width1", fiber, x, width1);
1764 if ((psfmodel == PROFILE_PSFEXP) ||
1765 (psfmodel == PROFILE_PSFEXP2)) {
1766 giraffe_psfdata_set(result,
"Width2", fiber, x, width2);
1780 cpl_matrix_delete(mx);
1783 cpl_matrix_delete(my);
1786 cpl_matrix_delete(ms);
1811inline static GiPsfData*
1812_giraffe_psf_fit_parameters1d(
const GiPsfData* psfdata,
1813 const cpl_table* fibers,
1814 const cxchar** names,
1816 const GiClipParams* setup)
1825 GiPsfData* psffit = NULL;
1828 cx_assert(psfdata != NULL);
1829 cx_assert(fibers != NULL);
1830 cx_assert(setup != NULL);
1832 ns = giraffe_psfdata_fibers(psfdata);
1833 nx = giraffe_psfdata_ysize(psfdata);
1834 ny = giraffe_psfdata_xsize(psfdata);
1836 psffit = giraffe_psfdata_create(ns, nx, ny, nx);
1838 giraffe_psfdata_set_model(psffit, giraffe_psfdata_get_model(psfdata));
1847 for (i = 0; i < ns; i++) {
1849 register cxint j = 0;
1851 for (j = 0; j < nx; j++) {
1852 giraffe_psfdata_set_bin(psffit, i, j, j);
1858 if (names == NULL) {
1861 cxsize count = giraffe_psfdata_parameters(psfdata);
1863 for (j = 0; j < count; j++) {
1865 const cxchar* name = giraffe_psfdata_get_name(psfdata, j);
1867 GiPsfParameterFit pfit = {NULL, NULL};
1870 pfit.fit = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
1871 pfit.coeffs = cpl_matrix_new(order + 1, ns);
1873 status = _giraffe_psf_fit_profile1d(&pfit, psfdata, name,
1874 fibers, order, setup);
1877 cpl_matrix_delete(pfit.coeffs);
1880 cpl_image_delete(pfit.fit);
1883 giraffe_psfdata_delete(psffit);
1889 giraffe_psfdata_set_data(psffit, name, pfit.fit);
1892 cpl_matrix_delete(pfit.coeffs);
1908 while (names[i] != NULL) {
1910 if (giraffe_psfdata_contains(psfdata, names[i]) == TRUE) {
1912 GiPsfParameterFit pfit = {NULL, NULL};
1915 pfit.fit = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
1916 pfit.coeffs = cpl_matrix_new(order + 1, ns);
1918 status = _giraffe_psf_fit_profile1d(&pfit, psfdata, names[i],
1919 fibers, order, setup);
1922 cpl_matrix_delete(pfit.coeffs);
1925 cpl_image_delete(pfit.fit);
1928 giraffe_psfdata_delete(psffit);
1934 giraffe_psfdata_set_data(psffit, names[i], pfit.fit);
1937 cpl_matrix_delete(pfit.coeffs);
1967inline static GiPsfData*
1968_giraffe_psf_fit_parameters(
const GiPsfData* psfdata,
1969 const cpl_table* fibers,
1970 const cxchar** names,
1971 cxint yorder, cxint worder,
1972 const GiClipParams* setup)
1975 const cxchar* center = NULL;
1983 GiPsfData* psffit = NULL;
1986 cx_assert(psfdata != NULL);
1987 cx_assert(fibers != NULL);
1988 cx_assert(names != NULL);
1989 cx_assert(setup != NULL);
1991 ns = giraffe_psfdata_fibers(psfdata);
1992 nx = giraffe_psfdata_ysize(psfdata);
1993 ny = giraffe_psfdata_xsize(psfdata);
1995 psffit = giraffe_psfdata_create(ns, nx, ny, nx);
1997 giraffe_psfdata_set_model(psffit, giraffe_psfdata_get_model(psfdata));
2006 for (i = 0; i < ns; i++) {
2008 register cxint j = 0;
2010 for (j = 0; j < nx; j++) {
2011 giraffe_psfdata_set_bin(psffit, i, j, j);
2017 if (giraffe_psfdata_contains(psfdata, center) == FALSE) {
2019 giraffe_psfdata_delete(psffit);
2027 GiPsfParameterFit pfit = {NULL, NULL};
2030 pfit.fit = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
2031 pfit.coeffs = cpl_matrix_new(yorder + 1, ns);
2033 status = _giraffe_psf_fit_profile1d(&pfit, psfdata, center, fibers,
2037 cpl_matrix_delete(pfit.coeffs);
2040 cpl_image_delete(pfit.fit);
2043 giraffe_psfdata_delete(psffit);
2049 giraffe_psfdata_set_data(psffit, center, pfit.fit);
2052 cpl_matrix_delete(pfit.coeffs);
2061 while (names[i] != NULL) {
2063 if (giraffe_psfdata_contains(psfdata, names[i]) == TRUE) {
2065 const cpl_image* xbin = giraffe_psfdata_get_bins(psfdata);
2066 const cpl_image* ybin = giraffe_psfdata_get_data(psfdata, center);
2067 const cpl_image* yfit = giraffe_psfdata_get_data(psffit, center);
2068 const cpl_image* pdata = giraffe_psfdata_get_data(psfdata,
2071 GiPsfParameterFit pfit = {NULL, NULL};
2074 pfit.fit = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
2075 pfit.coeffs = cpl_matrix_new(yorder + 1, worder + 1);
2077 status = _giraffe_psf_fit_profile2d(&pfit, fibers, pdata, xbin,
2078 ybin, yorder, worder, yfit,
2082 cpl_matrix_delete(pfit.coeffs);
2085 cpl_image_delete(pfit.fit);
2088 giraffe_psfdata_delete(psffit);
2094 giraffe_psfdata_set_data(psffit, names[i], pfit.fit);
2097 cpl_matrix_delete(pfit.coeffs);
2124_giraffe_psf_compute_mask(GiMaskPosition* positions, GiMaskPosition* coeffs,
2125 const GiPsfData* psfdata,
const cpl_table* fibers,
2126 cxint yorder, cxint worder,
2127 const GiClipParams* setup)
2130 const cxchar*
const lcenter =
"Center";
2131 const cxchar*
const lwidth =
"Width1";
2132 const cxchar*
const lexponent =
"Width2";
2133 const cxchar* model = NULL;
2141 const cpl_image* xbin = NULL;
2142 const cpl_image* ybin = NULL;
2143 cpl_image* width = NULL;
2145 GiPsfParameterFit center = {NULL, NULL};
2146 GiPsfParameterFit halfwidth = {NULL, NULL};
2148 GiProfileId psfmodel = 0;
2151 cx_assert((positions != NULL) &&
2152 (positions->type == GIMASK_FITTED_DATA) &&
2153 (positions->my != NULL) &&
2154 (positions->mw != NULL));
2155 cx_assert((coeffs != NULL) &&
2156 (coeffs->type == GIMASK_FIT_COEFFS) &&
2157 (coeffs->my != NULL) &&
2158 (coeffs->mw != NULL));
2159 cx_assert(psfdata != NULL);
2160 cx_assert(fibers != NULL);
2161 cx_assert(setup != NULL);
2163 model = giraffe_psfdata_get_model(psfdata);
2165 if (strcmp(model,
"psfexp") == 0) {
2166 psfmodel = PROFILE_PSFEXP;
2168 else if (strcmp(model,
"psfexp2") == 0) {
2169 psfmodel = PROFILE_PSFEXP2;
2171 else if (strcmp(model,
"gaussian") == 0) {
2172 psfmodel = PROFILE_GAUSSIAN;
2178 ns = giraffe_psfdata_fibers(psfdata);
2179 nx = giraffe_psfdata_ysize(psfdata);
2180 ny = giraffe_psfdata_xsize(psfdata);
2182 if ((cpl_matrix_get_nrow(positions->my) != nx) ||
2183 (cpl_matrix_get_ncol(positions->my) != ns) ||
2184 (cpl_matrix_get_nrow(positions->mw) != nx) ||
2185 (cpl_matrix_get_ncol(positions->mw) != ns)) {
2189 if ((cpl_matrix_get_nrow(coeffs->my) != yorder + 1) ||
2190 (cpl_matrix_get_ncol(coeffs->my) != ns)) {
2194 if ((cpl_matrix_get_nrow(coeffs->mw) != worder + 1) ||
2195 (cpl_matrix_get_ncol(coeffs->mw) != worder + 1)) {
2199 if (giraffe_psfdata_contains(psfdata, lcenter) == FALSE ||
2200 giraffe_psfdata_contains(psfdata, lwidth) == FALSE) {
2204 center.fit = cpl_image_wrap_double(ns, nx,
2205 cpl_matrix_get_data(positions->my));
2206 center.coeffs = coeffs->my;
2208 status = _giraffe_psf_fit_profile1d(¢er, psfdata, lcenter, fibers,
2212 cpl_image_unwrap(center.fit);
2215 center.coeffs = NULL;
2220 width = cpl_image_new(ns, nx, CPL_TYPE_DOUBLE);
2223 case PROFILE_PSFEXP:
2226 const cxdouble LOG2 = log(2.);
2228 if (giraffe_psfdata_contains(psfdata, lexponent) == FALSE) {
2229 cpl_image_delete(width);
2232 cpl_image_unwrap(center.fit);
2234 center.coeffs = NULL;
2239 for (i = 0; i < ns; i++) {
2241 register cxint j = 0;
2243 register cxdouble* _width = cpl_image_get_data_double(width);
2246 for (j = 0; j < nx; j++) {
2248 register cxint k = j * ns + i;
2251 giraffe_psfdata_get(psfdata, lwidth, i, j);
2253 giraffe_psfdata_get(psfdata, lexponent, i, j);
2256 _width[k] = 2. * pow(LOG2 * width1, 1. / width2);
2265 case PROFILE_PSFEXP2:
2268 const cxdouble LOG2 = log(2.);
2270 if (giraffe_psfdata_contains(psfdata, lexponent) == FALSE) {
2271 cpl_image_delete(width);
2274 cpl_image_unwrap(center.fit);
2276 center.coeffs = NULL;
2281 for (i = 0; i < ns; i++) {
2283 register cxint j = 0;
2285 register cxdouble* _width = cpl_image_get_data_double(width);
2288 for (j = 0; j < nx; j++) {
2290 register cxint k = j * ns + i;
2293 giraffe_psfdata_get(psfdata, lwidth, i, j);
2295 giraffe_psfdata_get(psfdata, lexponent, i, j);
2298 _width[k] = 2. * pow(LOG2, 1. / width2) * width1;
2307 case PROFILE_GAUSSIAN:
2310 const cxdouble fwhmscale = 4. * sqrt(2. * log(2.));
2312 for (i = 0; i < ns; i++) {
2314 register cxint j = 0;
2316 register cxdouble* _width = cpl_image_get_data_double(width);
2319 for (j = 0; j < nx; j++) {
2321 register cxint k = j * ns + i;
2323 _width[k] = fwhmscale *
2324 giraffe_psfdata_get(psfdata, lwidth, i, j);
2335 cpl_image_delete(width);
2338 cpl_image_unwrap(center.fit);
2340 center.coeffs = NULL;
2342 gi_error(
"Unsupported PSF profile model encountered!");
2347 xbin = giraffe_psfdata_get_bins(psfdata);
2348 ybin = giraffe_psfdata_get_data(psfdata, lcenter);
2351 halfwidth.fit = cpl_image_wrap_double(ns, nx,
2352 cpl_matrix_get_data(positions->mw));
2353 halfwidth.coeffs = coeffs->mw;
2355 status = _giraffe_psf_fit_profile2d(&halfwidth, fibers, width, xbin,
2356 ybin, worder, worder, center.fit,
2360 cpl_image_unwrap(halfwidth.fit);
2361 halfwidth.fit = NULL;
2362 halfwidth.coeffs = NULL;
2364 cpl_image_delete(width);
2367 cpl_image_unwrap(center.fit);
2369 center.coeffs = NULL;
2374 cpl_image_unwrap(halfwidth.fit);
2375 halfwidth.fit = NULL;
2376 halfwidth.coeffs = NULL;
2378 cpl_image_delete(width);
2381 cpl_image_unwrap(center.fit);
2383 center.coeffs = NULL;
2390inline static cpl_image*
2391_giraffe_psf_simulate_mask(
const GiPsfData* psfdata,
2392 const cpl_image* amplitude,
2393 const cpl_image* background,
2397 const cxchar* model = NULL;
2407 cxdouble bsize = 1.;
2408 cxdouble _bsize = 1.;
2409 cxdouble* _mask = NULL;
2411 const cpl_image* center = NULL;
2412 const cpl_image* width = NULL;
2413 const cpl_image* exponent = NULL;
2415 cpl_image* mask = NULL;
2417 GiModel* profile = NULL;
2419 GiProfileId psfmodel = 0;
2422 cx_assert(psfdata != NULL);
2424 model = giraffe_psfdata_get_model(psfdata);
2426 if (strcmp(model,
"psfexp") == 0) {
2427 psfmodel = PROFILE_PSFEXP;
2429 else if (strcmp(model,
"psfexp2") == 0) {
2430 psfmodel = PROFILE_PSFEXP2;
2432 else if (strcmp(model,
"gaussian") == 0) {
2433 psfmodel = PROFILE_GAUSSIAN;
2439 nfibers = giraffe_psfdata_fibers(psfdata);
2440 nbins = giraffe_psfdata_bins(psfdata);
2441 nx = giraffe_psfdata_ysize(psfdata);
2442 ny = giraffe_psfdata_xsize(psfdata);
2444 center = giraffe_psfdata_get_data(psfdata,
"Center");
2445 width = giraffe_psfdata_get_data(psfdata,
"Width1");
2446 exponent = giraffe_psfdata_get_data(psfdata,
"Width2");
2448 if (amplitude == NULL) {
2449 amplitude = giraffe_psfdata_get_data(psfdata,
"Amplitude");
2452 if ((cpl_image_get_size_x(amplitude) != nfibers) ||
2453 (cpl_image_get_size_y(amplitude) > nbins)) {
2458 if (background == NULL) {
2459 background = giraffe_psfdata_get_data(psfdata,
"Background");
2462 if ((cpl_image_get_size_x(background) != nfibers) ||
2463 (cpl_image_get_size_y(background) > nbins)) {
2468 bsize = (cxdouble)nx / (cxdouble)nbins;
2470 _nbins = cpl_image_get_size_y(amplitude);
2471 _bsize = (cxdouble)nx / (cxdouble)_nbins;
2473 mask = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
2474 _mask = cpl_image_get_data_double(mask);
2476 profile = giraffe_model_new(model);
2478 for (fiber = 0; fiber < nfibers; fiber++) {
2483 const cxdouble* _amplitude =
2484 cpl_image_get_data_double_const(amplitude);
2485 const cxdouble* _center =
2486 cpl_image_get_data_double_const(center);
2487 const cxdouble* _width =
2488 cpl_image_get_data_double_const(width);
2489 const cxdouble* _exponent =
2490 cpl_image_get_data_double_const(exponent);
2492 for (i = 0; i < nx; i++) {
2494 register cxint j = 0;
2495 register cxint k = 0;
2496 register cxint l = 0;
2497 register cxint bin = 0;
2499 register cxdouble a = 1.;
2500 register cxdouble b = 0.;
2501 register cxdouble c = 0.;
2502 register cxdouble s = 0.;
2503 register cxdouble e = 0.;
2506 bin = CX_MAX(0, CX_MIN((cxint)floor(i / bsize), nbins - 1));
2507 k = bin * nfibers + fiber;
2509 bin = CX_MAX(0, CX_MIN((cxint)floor(i / _bsize), _nbins - 1));
2510 l = bin * nfibers + fiber;
2517 giraffe_model_set_parameter(profile,
"Amplitude", a);
2518 giraffe_model_set_parameter(profile,
"Background", b);
2519 giraffe_model_set_parameter(profile,
"Center", c);
2520 giraffe_model_set_parameter(profile,
"Width1", s);
2521 giraffe_model_set_parameter(profile,
"Width2", e);
2524 case PROFILE_PSFEXP:
2526 cxdouble w = pow(s * log(1. / cutoff), 1. / e);
2528 ylower = (cxint) floor(c - w);
2529 yupper = (cxint) ceil(c + w);
2533 case PROFILE_PSFEXP2:
2535 cxdouble w = s * pow(log(1. / cutoff), 1. / e);
2537 ylower = (cxint) floor(c - w);
2538 yupper = (cxint) ceil(c + w);
2542 case PROFILE_GAUSSIAN:
2544 cxdouble w = s * sqrt(log(1. / cutoff));
2545 ylower = (cxint) floor(c - w);
2546 yupper = (cxint) ceil(c + w);
2551 gi_error(
"Unsupported PSF profile model encountered!");
2555 ylower = CX_MAX(0, ylower);
2556 yupper = CX_MIN(ny, yupper);
2558 for (j = ylower; j < yupper; j++) {
2562 cxdouble value = 0.;
2568 giraffe_model_set_argument(profile,
"x", j);
2569 giraffe_model_evaluate(profile, &value, &status);
2571 _mask[i * ny + j] += value;
2579 giraffe_model_delete(profile);
2600 GiTable* fibers, GiLocalization* master,
2601 GiImage* bpixel, GiPsfConfig* config)
2604 const cxchar*
const _func =
"giraffe_compute_fiber_profiles";
2614 cxdouble conad = 1.;
2615 cxdouble bias_ron = 0.;
2616 cxdouble bias_sigma = 0.;
2617 cxdouble dark_value = 0.;
2619 cx_string* s = NULL;
2621 cpl_table* _fibers = NULL;
2622 cpl_table* locc = NULL;
2624 cpl_matrix* my = NULL;
2626 cpl_image* _image = NULL;
2627 cpl_image* _variance = NULL;
2628 cpl_image* _locy = NULL;
2629 cpl_image* _locw = NULL;
2630 cpl_image* _bpixel = NULL;
2632 cpl_propertylist* properties = NULL;
2634 GiModel* psfmodel = NULL;
2636 GiPsfData* psfdata = NULL;
2637 GiPsfData* psffit = NULL;
2639 GiMaskPosition positions = {GIMASK_FITTED_DATA, NULL, NULL};
2640 GiMaskPosition coeffs = {GIMASK_FIT_COEFFS, NULL, NULL};
2642 GiPsfParams psf_setup = {0, 0, 1000., FALSE};
2645 if ((result == NULL) || (image == NULL) || (fibers == NULL) ||
2646 (master == NULL) || (config == NULL)) {
2647 cpl_error_set(_func, CPL_ERROR_NULL_INPUT);
2651 if ((master->locy == NULL) || (master->locw == NULL)) {
2652 cpl_error_set(_func, CPL_ERROR_NULL_INPUT);
2656 if ((result->locy != NULL) || (result->locw != NULL) ||
2657 (result->locc != NULL) || (result->psf != NULL)) {
2658 cpl_error_set(_func, CPL_ERROR_ILLEGAL_INPUT);
2666 if (bpixel != NULL) {
2672 if (_fibers == NULL) {
2673 cpl_error_set(_func, CPL_ERROR_DATA_NOT_FOUND);
2677 nfibers = cpl_table_get_nrow(_fibers);
2679 nx = cpl_image_get_size_y(_image);
2680 ny = cpl_image_get_size_x(_image);
2682 nbins = (cxint) ceil(nx / config->binsize);
2691 if (cpl_propertylist_has(properties, GIALIAS_NFIBERS) == FALSE) {
2692 cpl_propertylist_append_int(properties, GIALIAS_NFIBERS, nfibers);
2693 cpl_propertylist_set_comment(properties, GIALIAS_NFIBERS,
2694 "Number of fibres");
2698 cxint _nfibers = cpl_propertylist_get_int(properties,
2701 if (nfibers != _nfibers) {
2702 cpl_error_set(_func, CPL_ERROR_ILLEGAL_INPUT);
2709 giraffe_error_push();
2713 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2717 giraffe_error_pop();
2720 if (!cpl_propertylist_has(properties, GIALIAS_BIASERROR)) {
2721 cpl_msg_warning(_func,
"Missing bias error property (%s)! Setting "
2722 "bias error to 0.", GIALIAS_BIASERROR);
2726 bias_sigma = cpl_propertylist_get_double(properties, GIALIAS_BIASERROR);
2730 giraffe_error_push();
2734 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2738 giraffe_error_pop();
2741 if (cpl_propertylist_has(properties, GIALIAS_DARKVALUE) == FALSE) {
2742 cpl_msg_warning(_func,
"Missing dark value property (%s) will be "
2743 "set to %.2f!", GIALIAS_DARKVALUE, dark_value);
2744 cpl_propertylist_append_double(properties, GIALIAS_DARKVALUE,
2748 dark_value = cpl_propertylist_get_double(properties,
2753 if (cpl_propertylist_has(properties, GIALIAS_DATANCOM)) {
2754 nframes = cpl_propertylist_get_int(properties, GIALIAS_DATANCOM);
2762 bias_sigma *= conad;
2763 dark_value *= conad;
2770 giraffe_error_push();
2772 _image = cpl_image_multiply_scalar_create(_image, nframes * conad);
2773 _variance = cpl_image_abs_create(_image);
2775 cpl_image_add_scalar(_variance,
2776 nframes * (bias_ron * bias_ron + nframes *
2777 (bias_sigma * bias_sigma + dark_value * dark_value)));
2779 if (cpl_error_get_code() != CPL_ERROR_NONE) {
2780 if (_variance != NULL) {
2781 cpl_image_delete(_variance);
2785 cpl_image_delete(_image);
2791 giraffe_error_pop();
2798 psfmodel = giraffe_model_new(config->profile);
2800 giraffe_model_thaw(psfmodel);
2802 giraffe_model_set_parameter(psfmodel,
"Amplitude", 1.);
2803 giraffe_model_set_parameter(psfmodel,
"Background", 0.);
2804 giraffe_model_set_parameter(psfmodel,
"Center", 0.);
2805 giraffe_model_set_parameter(psfmodel,
"Width1", config->width);
2807 if (cx_strncasecmp(config->profile,
"psfexp", 6) == 0) {
2809 cxdouble _exponent = fabs(config->exponent);
2811 giraffe_model_set_parameter(psfmodel,
"Width2", _exponent);
2813 if (config->exponent > 0) {
2814 giraffe_model_freeze_parameter(psfmodel,
"Width2");
2819 giraffe_model_set_iterations(psfmodel, config->fit.iterations);
2820 giraffe_model_set_delta(psfmodel, config->fit.delta);
2821 giraffe_model_set_tests(psfmodel, config->fit.tests);
2829 cpl_msg_info(_func,
"Fitting fiber profiles ...");
2831 psf_setup.bsize = config->binsize;
2832 psf_setup.mwidth = config->maxwidth;
2833 psf_setup.normalize = config->normalize;
2835 psfdata = giraffe_psfdata_create(nfibers, nbins, ny, nx);
2837 status = _giraffe_psf_compute_profile(psfdata, _image, _variance, _locy,
2838 _locw, _fibers, _bpixel, psfmodel,
2841 cpl_image_delete(_image);
2845 giraffe_psfdata_delete(psfdata);
2848 giraffe_model_delete(psfmodel);
2851 cpl_image_delete(_variance);
2854 cpl_msg_error(_func,
"Fiber profile fit failed!");
2865 _image = (cpl_image*) giraffe_psfdata_get_data(psfdata,
"Amplitude");
2866 cpl_image_divide_scalar(_image, nframes * conad);
2868 _image = (cpl_image*) giraffe_psfdata_get_data(psfdata,
"Background");
2869 cpl_image_divide_scalar(_image, nframes * conad);
2879 cpl_msg_info(_func,
"Fitting PSF profile parameters ...");
2881 if (config->parameter_fit == TRUE) {
2883 const cxchar* parameters[] = {
"Center",
"Amplitude",
"Background",
2884 "Width1",
"Width2", NULL};
2886 psffit = _giraffe_psf_fit_parameters(psfdata, _fibers, parameters,
2887 config->yorder, config->worder,
2893 psffit = _giraffe_psf_fit_parameters1d(psfdata, _fibers,
2894 NULL, config->yorder,
2899 if (psffit == NULL) {
2900 giraffe_psfdata_delete(psfdata);
2903 giraffe_model_delete(psfmodel);
2906 cpl_image_delete(_variance);
2909 cpl_msg_error(_func,
"PSF parameter fit failed!");
2913 giraffe_model_delete(psfmodel);
2916 cpl_image_delete(_variance);
2924 positions.my = cpl_matrix_new(nx, nfibers);
2925 positions.mw = cpl_matrix_new(nx, nfibers);
2927 coeffs.my = cpl_matrix_new(config->yorder + 1, nfibers);
2928 coeffs.mw = cpl_matrix_new(config->worder + 1, config->worder + 1);
2930 status = _giraffe_psf_compute_mask(&positions, &coeffs, psfdata, _fibers,
2931 config->yorder, config->worder,
2936 giraffe_psfdata_delete(psffit);
2939 giraffe_psfdata_delete(psfdata);
2942 cpl_msg_error(_func,
"Computation of localization mask from "
2943 "the fiber profile failed!");
2948 giraffe_psfdata_delete(psfdata);
2959 cpl_propertylist_update_string(properties, GIALIAS_PSFMODEL,
2961 cpl_propertylist_set_comment(properties, GIALIAS_PSFMODEL,
2962 "PSF profile model identifier");
2964 cpl_propertylist_update_int(properties, GIALIAS_PSFXBINS,
2966 cpl_propertylist_set_comment(properties, GIALIAS_PSFXBINS,
2967 "Size of bins along the dispersion "
2970 cpl_propertylist_update_int(properties, GIALIAS_PSFYDEG,
2972 cpl_propertylist_set_comment(properties, GIALIAS_PSFYDEG,
2973 "Order of the fiber center polynomial "
2976 cpl_propertylist_update_int(properties, GIALIAS_PSFWDEG,
2978 cpl_propertylist_set_comment(properties, GIALIAS_PSFWDEG,
2979 "Order of the fiber width 2d polynomial "
2982 cpl_propertylist_update_int(properties, GIALIAS_PSFWDEG,
2984 cpl_propertylist_set_comment(properties, GIALIAS_PSFWDEG,
2985 "Order of the fiber width 2d polynomial "
2988 cpl_propertylist_update_bool(properties, GIALIAS_PSFNORM,
2990 cpl_propertylist_set_comment(properties, GIALIAS_PSFNORM,
2991 "Pixel value normalization.");
2993 cpl_propertylist_update_int(properties, GIALIAS_PSFNX,
2994 cpl_matrix_get_nrow(positions.my));
2995 cpl_propertylist_set_comment(properties, GIALIAS_PSFNX,
2996 "Number of pixels per spectrum.");
2998 cpl_propertylist_update_int(properties, GIALIAS_PSFNS,
2999 cpl_matrix_get_ncol(positions.my));
3000 cpl_propertylist_set_comment(properties, GIALIAS_PSFNS,
3001 "Number of detected fibers.");
3003 cpl_propertylist_update_double(properties, GIALIAS_PSFSIGMA,
3004 config->clip.level);
3005 cpl_propertylist_set_comment(properties, GIALIAS_PSFSIGMA,
3006 "Sigma multiplier used for the PSF "
3009 cpl_propertylist_update_double(properties, GIALIAS_PSFSIGMA,
3010 config->clip.level);
3011 cpl_propertylist_set_comment(properties, GIALIAS_PSFSIGMA,
3012 "Sigma multiplier used for the fit of PSF "
3015 cpl_propertylist_update_int(properties, GIALIAS_PSFNITER,
3016 config->clip.iterations);
3017 cpl_propertylist_set_comment(properties, GIALIAS_PSFNITER,
3018 "Number of iterations used for the fit "
3019 "of PSF parameters.");
3021 cpl_propertylist_update_double(properties, GIALIAS_PSFMFRAC,
3022 config->clip.fraction);
3023 cpl_propertylist_set_comment(properties, GIALIAS_PSFMFRAC,
3024 "Minimum allowed fraction of accepted "
3025 "over total data points used for the "
3026 "fit of PSF parameters.");
3032 cpl_matrix_get_ncol(positions.my),
3033 cpl_matrix_get_nrow(positions.my));
3036 cpl_matrix_delete(positions.my);
3037 positions.my = NULL;
3042 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
"LOCY");
3043 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
3044 "GIRAFFE localization centroid");
3050 cpl_matrix_get_ncol(positions.mw),
3051 cpl_matrix_get_nrow(positions.mw));
3054 cpl_matrix_delete(positions.mw);
3055 positions.mw = NULL;
3062 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
"LOCWY");
3063 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
3064 "GIRAFFE localization half-width");
3069 locc = cpl_table_new(cpl_matrix_get_ncol(coeffs.my));
3071 cpl_table_new_column(locc,
"BUTTON", CPL_TYPE_INT);
3072 for (i = 0; i < cpl_table_get_nrow(locc); i++) {
3073 cpl_table_set_int(locc,
"BUTTON", i, i);
3076 for (i = 0; i < cpl_matrix_get_nrow(coeffs.my); i++) {
3078 cxchar* label = NULL;
3080 cx_asprintf(&label,
"YC%d", i);
3081 cpl_table_new_column(locc, label, CPL_TYPE_DOUBLE);
3091 cpl_table_delete(locc);
3094 my = cpl_matrix_transpose_create(coeffs.my);
3097 cpl_matrix_delete(my);
3100 cpl_matrix_delete(coeffs.my);
3106 s = cx_string_new();
3108 for (i = 0; i < cpl_matrix_get_ncol(coeffs.mw); i++) {
3109 cx_string_sprintf(s,
"%s%d", GIALIAS_LOCWIDCOEF, i);
3110 cpl_propertylist_update_double(properties, cx_string_get(s),
3111 cpl_matrix_get(coeffs.mw, 0, i));
3114 cx_string_delete(s);
3117 cpl_matrix_delete(coeffs.mw);
3120 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
3122 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
3123 "GIRAFFE localization fit coefficients");
3128 if (psffit != NULL) {
3129 result->psf = psffit;
3153 GiPsfConfig *self = NULL;
3160 self = cx_calloc(1,
sizeof *self);
3162 p = cpl_parameterlist_find(list,
"giraffe.psf.model");
3163 self->profile = cx_strdup(cpl_parameter_get_string(p));
3165 if (cx_strncasecmp(self->profile,
"psfexp", 6) == 0) {
3172 p = cpl_parameterlist_find(list,
"giraffe.psf.binsize");
3173 self->binsize = cpl_parameter_get_int(p);
3175 if (self->binsize < 1) {
3179 p = cpl_parameterlist_find(list,
"giraffe.psf.maxwidth");
3180 self->maxwidth = cpl_parameter_get_double(p);
3182 if (self->width > 0.) {
3183 p = cpl_parameterlist_find(list,
"giraffe.psf.width");
3184 self->width = cpl_parameter_get_double(p);
3187 if (self->width > self->maxwidth) {
3188 self->width = self->maxwidth;
3191 p = cpl_parameterlist_find(list,
"giraffe.psf.exponent");
3192 self->exponent = cpl_parameter_get_double(p);
3194 p = cpl_parameterlist_find(list,
"giraffe.psf.normalize");
3195 self->normalize = cpl_parameter_get_bool(p);
3197 p = cpl_parameterlist_find(list,
"giraffe.psf.profile.iterations");
3198 self->fit.iterations = cpl_parameter_get_int(p);
3200 p = cpl_parameterlist_find(list,
"giraffe.psf.profile.tests");
3201 self->fit.tests = cpl_parameter_get_int(p);
3203 p = cpl_parameterlist_find(list,
"giraffe.psf.profile.dchisquare");
3204 self->fit.delta = cpl_parameter_get_double(p);
3206 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.fit");
3207 self->parameter_fit = cpl_parameter_get_bool(p);
3209 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.yorder");
3210 self->yorder = cpl_parameter_get_int(p);
3212 if (self->yorder < 0) {
3217 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.worder");
3218 self->worder = cpl_parameter_get_int(p);
3220 if (self->worder < 0) {
3225 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.sigma");
3226 self->clip.level = cpl_parameter_get_double(p);
3228 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.iterations");
3229 self->clip.iterations = cpl_parameter_get_int(p);
3231 p = cpl_parameterlist_find(list,
"giraffe.psf.parameters.fraction");
3232 self->clip.fraction = cpl_parameter_get_double(p);
3256 if (self->profile != NULL) {
3257 cx_free((cxptr) self->profile);
3258 self->profile = NULL;
3284 cpl_parameter* p = NULL;
3291 p = cpl_parameter_new_enum(
"giraffe.psf.model",
3293 "PSF profile model: `psfexp', `psfexp2'",
3295 "psfexp2", 3,
"psfexp",
"psfexp2",
"gaussian");
3296 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-model");
3297 cpl_parameterlist_append(list, p);
3299 p = cpl_parameter_new_value(
"giraffe.psf.normalize",
3301 "Use normalized pixel values.",
3304 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-norm");
3305 cpl_parameterlist_append(list, p);
3308 p = cpl_parameter_new_value(
"giraffe.psf.binsize",
3310 "Size of bin along dispersion axis",
3313 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-binsize");
3314 cpl_parameterlist_append(list, p);
3317 p = cpl_parameter_new_value(
"giraffe.psf.maxwidth",
3319 "Maximum width of the PSF profile.",
3322 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-maxwidth");
3323 cpl_parameterlist_append(list, p);
3326 p = cpl_parameter_new_value(
"giraffe.psf.width",
3328 "Initial width of the PSF profile.",
3331 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-width");
3332 cpl_parameterlist_append(list, p);
3335 p = cpl_parameter_new_value(
"giraffe.psf.exponent",
3337 "Exponent of the exponential PSF profile "
3338 "(will not be fitted if > 0).",
3341 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-exponent");
3342 cpl_parameterlist_append(list, p);
3345 p = cpl_parameter_new_value(
"giraffe.psf.profile.iterations",
3347 "Maximum number of iterations used for "
3348 "the fit of the fiber PSF profile.",
3352 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-pfniter");
3353 cpl_parameterlist_append(list, p);
3356 p = cpl_parameter_new_value(
"giraffe.psf.profile.tests",
3358 "Maximum number of tests used for the fit "
3359 "of the fiber PSF profile",
3363 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-pfntest");
3364 cpl_parameterlist_append(list, p);
3367 p = cpl_parameter_new_value(
"giraffe.psf.profile.dchisquare",
3369 "Minimum chi-square difference used for the "
3370 "fit of the fiber PSF profile.",
3374 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-pfdchisq");
3375 cpl_parameterlist_append(list, p);
3378 p = cpl_parameter_new_value(
"giraffe.psf.parameters.fit",
3380 "2D fit of the PSF profile parameters "
3381 "using a Chebyshev polynomial model.",
3384 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-prmfit");
3385 cpl_parameterlist_append(list, p);
3388 p = cpl_parameter_new_value(
"giraffe.psf.parameters.yorder",
3390 "Order of Chebyshev polynomial fit.",
3393 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-yorder");
3394 cpl_parameterlist_append(list, p);
3397 p = cpl_parameter_new_value(
"giraffe.psf.parameters.worder",
3399 "Order of Chebyshev 2D polynomial fit.",
3402 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-worder");
3403 cpl_parameterlist_append(list, p);
3406 p = cpl_parameter_new_value(
"giraffe.psf.parameters.sigma",
3408 "PSF parameter fitting: sigma threshold "
3412 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-sigma");
3413 cpl_parameterlist_append(list, p);
3416 p = cpl_parameter_new_value(
"giraffe.psf.parameters.iterations",
3418 "PSF parameter fitting: number of "
3422 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-niter");
3423 cpl_parameterlist_append(list, p);
3426 p = cpl_parameter_new_range(
"giraffe.psf.parameters.fraction",
3428 "PSF parameter fitting: minimum fraction "
3429 "of points accepted/total.",
3432 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"psf-mfrac");
3433 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_image * giraffe_image_get(const GiImage *self)
Gets the image data.
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
GiImage * giraffe_image_create(cpl_type type, cxint nx, cxint ny)
Creates an image container of a given type.
cxint giraffe_image_copy_matrix(GiImage *self, cpl_matrix *matrix)
Copies matrix elements into an image.
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.
GiTable * giraffe_table_create(cpl_table *table, cpl_propertylist *properties)
Creates a Giraffe table from a table and a property list.
cxint giraffe_table_copy_matrix(GiTable *table, const cxchar *name, cpl_matrix *matrix)
Copies matrix elements into a table.
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
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.