34 #if CPL_VERSION_CODE >= 394496
35 #include <cpl_multiframe.h>
41 #ifdef HAVE_GETTIMEOFDAY
45 #include "muse_utils.h"
46 #include "muse_instrument.h"
48 #include "muse_cplwrappers.h"
49 #include "muse_pfits.h"
50 #include "muse_resampling.h"
51 #include "muse_tracing.h"
57 #define MOFFAT_USE_MUSE_OPTIMIZE 0
59 #if MOFFAT_USE_MUSE_OPTIMIZE
60 #include "muse_optimize.h"
86 return cpl_get_license(PACKAGE_NAME,
"2005, 2014");
102 for (n = 1; n <= kMuseNumIFUs; n++) {
121 cpl_errorstate prestate = cpl_errorstate_get();
122 int i, next = cpl_fits_count_extensions(aFilename);
123 for (i = 0; i <= next; i++) {
124 cpl_propertylist *properties = cpl_propertylist_load(aFilename, i);
126 cpl_propertylist_delete(properties);
129 cpl_propertylist_delete(properties);
131 cpl_errorstate_set(prestate);
159 unsigned char aIFU, cpl_boolean aInvert)
161 cpl_ensure(aFrames, CPL_ERROR_NULL_INPUT, NULL);
162 cpl_frameset *newFrames = cpl_frameset_new();
165 cpl_size iframe, nframes = cpl_frameset_get_size(aFrames);
166 for (iframe = 0; iframe < nframes; iframe++) {
167 const cpl_frame *frame = cpl_frameset_get_position_const(aFrames, iframe);
168 const char *fn = cpl_frame_get_filename(frame),
169 *tag = cpl_frame_get_tag(frame);
173 cpl_boolean matched = !aInvert && (!aTag || (aTag && !strcmp(tag, aTag))),
175 && ((aTag && !tag) || (aTag && strcmp(tag, aTag)));
176 if (matched || unmatched) {
179 cpl_errorstate prestate = cpl_errorstate_get();
183 if (extension == -1) {
185 cpl_errorstate_set(prestate);
187 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
189 prestate = cpl_errorstate_get();
191 if (!cpl_errorstate_is_equal(prestate)) {
193 cpl_errorstate_set(prestate);
197 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
198 }
else if (ifu == 0 && !pipefile) {
201 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
202 }
else if (aIFU == 0) {
204 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
205 }
else if (!strncmp(aTag,
"GEOMETRY_TABLE", 15)) {
208 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
212 cpl_msg_debug(__func__,
"not added %s / %s / %d", fn,
213 cpl_frame_get_tag(frame), ifu);
216 cpl_propertylist_delete(header);
244 unsigned char aIFU, cpl_boolean aInvert)
246 cpl_ensure(aFrames && aTags, CPL_ERROR_NULL_INPUT, NULL);
247 cpl_ensure(cpl_array_get_type(aTags) == CPL_TYPE_STRING,
248 CPL_ERROR_ILLEGAL_INPUT, NULL);
250 cpl_frameset *outframes = cpl_frameset_new();
251 cpl_size itag, ntags = cpl_array_get_size(aTags);
252 for (itag = 0; itag < ntags; itag++) {
253 const char *tag = cpl_array_get_string(aTags, itag);
255 cpl_frameset_join(outframes, frames);
256 cpl_frameset_delete(frames);
279 cpl_frameset *newFrames = cpl_frameset_new();
282 cpl_size iframe, nframes = cpl_frameset_get_size(foundFrames);
283 cpl_msg_debug(__func__,
"Determine properties of all %"CPL_SIZE_FORMAT
284 " raw frames of IFU %hhu", nframes, aIFU);
285 int binx = -1, biny = -1, readid = -1;
286 char *fn = NULL, *readname = NULL, *chipname = NULL, *chipid = NULL;
287 for (iframe = 0; iframe < nframes; iframe++) {
288 const cpl_frame *frame = cpl_frameset_get_position_const(foundFrames, iframe);
291 const char *fn2 = cpl_frame_get_filename(frame);
293 fn = cpl_strdup(fn2);
295 cpl_propertylist *header = cpl_propertylist_load(fn2, 0);
298 cpl_propertylist *exthead = cpl_propertylist_load(fn2, extension);
299 cpl_propertylist_append(header, exthead);
300 cpl_propertylist_delete(exthead);
303 cpl_msg_warning(__func__,
"Cannot read FITS header of file \"%s\"!", fn2);
306 cpl_boolean isOK = CPL_TRUE;
331 cpl_msg_warning(__func__,
"File \"%s\" (IFU %hhu) was taken with a different"
332 " x-binning factor (reference \"%s\", %d instead of %d)!",
333 fn2, aIFU, fn, binx2, binx);
337 cpl_msg_warning(__func__,
"File \"%s\" (IFU %hhu) was taken with a different"
338 " y-binning factor (reference \"%s\", %d instead of %d)!",
339 fn2, aIFU, fn, biny2, biny);
342 if (readid2 != readid) {
343 cpl_msg_warning(__func__,
"File \"%s\" (IFU %hhu) was taken with a different"
344 " read-out mode (reference \"%s\", %d/%s instead of %d/%s)!",
349 if (!chipname2 || !chipid2 ||
350 strcmp(chipname, chipname2) || strcmp(chipid, chipid2)) {
351 cpl_msg_warning(__func__,
"File \"%s\" (IFU %hhu) has a different chip "
352 "setup (reference \"%s\", name %s vs %s, id %s vs %s)",
353 fn2, aIFU, fn, chipname2, chipname, chipid2, chipid);
357 if (!cpl_frame_get_tag(frame) ||
358 !strncmp(cpl_frame_get_tag(frame), MUSE_TAG_EMPTY, 1) ) {
361 cpl_msg_warning(__func__,
"File \"%s\" (IFU %hhu) is not tagged!", fn2,
364 cpl_propertylist_delete(header);
366 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
373 cpl_frameset_delete(foundFrames);
400 const char *aDateObs, cpl_boolean aSequence)
402 cpl_ensure(aFrames, CPL_ERROR_NULL_INPUT, NULL);
404 cpl_frameset *fraw = cpl_frameset_new(),
405 *fother = cpl_frameset_new();
407 cpl_size iframe, nframes = cpl_frameset_get_size(aFrames);
408 for (iframe = 0; iframe < nframes; iframe++) {
409 const cpl_frame *frame = cpl_frameset_get_position_const(aFrames, iframe);
410 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_RAW) {
414 cpl_propertylist *header
415 = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
417 datematch = !strncmp(aDateObs, dateobs, strlen(aDateObs));
418 cpl_propertylist_delete(header);
420 if ((aIndex < 0 && datematch) || aIndex == iraw || aSequence) {
421 cpl_frameset_insert(fraw, cpl_frame_duplicate(frame));
425 cpl_frameset_insert(fother, cpl_frame_duplicate(frame));
429 printf(
"incoming frames (index=%d, DATE-OBS=%s):\n", aIndex, aDateObs);
430 cpl_frameset_dump(aFrames, stdout);
432 printf(
"=============================================================\n"
434 cpl_frameset_dump(fraw, stdout);
436 printf(
"-------------------------------------------------------------\n"
438 cpl_frameset_dump(fother, stdout);
443 cpl_frameset_join(fraw, fother);
444 cpl_frameset_delete(fother);
446 printf(
"=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=\n"
447 "all sorted frames:\n");
448 cpl_frameset_dump(fraw, stdout);
472 cpl_frame *frame = NULL;
473 if (cpl_frameset_count_tags(frames, aTag) == 1) {
474 frame = cpl_frame_duplicate(cpl_frameset_get_position_const(frames, 0));
476 cpl_frameset_delete(frames);
480 #if CPL_VERSION_CODE >= 394330
486 muse_utils_frame_get_basefilename(
const cpl_frame *aFrame)
488 char *filename = cpl_strdup(cpl_frame_get_filename(aFrame)),
489 *end = strstr(filename,
".fits");
493 end = strrchr(filename,
'-');
497 char *fn = cpl_sprintf(
"%s.fits", filename);
505 muse_utils_frames_compare_basenames(
const cpl_frame *aF1,
const cpl_frame *aF2)
507 cpl_ensure(aF1 && aF2, CPL_ERROR_NULL_INPUT, -1);
508 cpl_ensure(cpl_frame_get_filename(aF1) && cpl_frame_get_filename(aF2),
509 CPL_ERROR_DATA_NOT_FOUND, -1);
510 char *fn1 = muse_utils_frame_get_basefilename(aF1),
511 *fn2 = muse_utils_frame_get_basefilename(aF2);
512 int cmp = strcmp(fn1, fn2);
515 return cmp == 0 ? 1 : 0;
520 _muse_utils_frame_compare(
const cpl_frame *
self,
521 const cpl_frame *other)
523 const char *_self = cpl_frame_get_filename(
self);
524 const char *_other = cpl_frame_get_filename(other);
526 int cmp = strcmp(_self, _other);
531 #if CPL_VERSION_CODE < 394497
532 return (cmp < 0) ? 1 : (cmp > 0) ? -1 : 0;
534 return (cmp < 0) ? -1 : (cmp > 0) ? 1 : 0;
541 muse_utils_frameset_merge_frames(cpl_frameset *aFrames)
543 cpl_ensure_code(aFrames, CPL_ERROR_NULL_INPUT);
545 printf(
"final out frames:\n");
546 cpl_frameset_dump(aFrames, stdout);
550 #if CPL_VERSION_CODE >= 394496
553 #define EXTKEYS1 MUSE_WCS_KEYS"|(ESO DET (CHIP|OUT[1-9]*) |ESO QC|ESO DRS)"
554 #define EXTKEYS2 MUSE_WCS_KEYS"|^B(UNIT|SCALE|ZERO)"
555 cpl_regex *regex = cpl_regex_new(EXTKEYS1, TRUE, CPL_REGEX_EXTENDED),
556 *nregex = cpl_regex_new(EXTKEYS1, FALSE, CPL_REGEX_EXTENDED),
557 *nregex2 = cpl_regex_new(EXTKEYS1
"|"EXTKEYS2, FALSE,
561 cpl_frameset *frames = cpl_frameset_new();
564 cpl_size nlabels = 0;
565 cpl_size *labels = cpl_frameset_labelise(aFrames,
566 muse_utils_frames_compare_basenames,
568 for (ilabel = 0; ilabel < nlabels; ilabel++) {
569 cpl_frameset *fset = cpl_frameset_extract(aFrames, labels, ilabel);
571 int i, n = cpl_frameset_get_size(fset);
573 cpl_frameset_sort(fset, _muse_utils_frame_compare);
575 cpl_frame *frame = cpl_frameset_get_position(fset, 0);
576 const char *tag = cpl_frame_get_tag(frame);
582 if (strncmp(tag,
"PIXTABLE_", 9) == 0) {
583 cpl_frameset_delete(fset);
588 cpl_msg_warning(__func__,
"Nothing to merge for tag %s (%d frames)!",
590 cpl_frameset_delete(fset);
593 cpl_multiframe *mf = cpl_multiframe_new(frame,
"", regex);
595 cpl_frameset_delete(fset);
600 for (i = 0; i < n; i++) {
601 frame = cpl_frameset_get_position(fset, i);
602 const char *fn = cpl_frame_get_filename(frame);
603 cpl_msg_debug(__func__,
"Merging \"%s\".", fn);
605 int extdata = cpl_fits_find_extension(fn, EXTNAME_DATA),
606 extdq = cpl_fits_find_extension(fn, EXTNAME_DQ),
607 extstat = cpl_fits_find_extension(fn, EXTNAME_STAT);
608 cpl_errorstate state = cpl_errorstate_get();
609 if (extdata > 0 && extdq > 0 && extstat > 0) {
611 const char *extnames[] = { EXTNAME_DATA, EXTNAME_DQ, EXTNAME_STAT },
612 *updkeys[] = {
"SCIDATA",
"ERRDATA",
"QUALDATA", NULL };
613 const cpl_regex *filters[] = { nregex, nregex, nregex };
614 cpl_multiframe_append_datagroup(mf,
".", frame, 3, extnames, filters,
615 NULL, updkeys, CPL_MULTIFRAME_ID_JOIN);
616 }
else if (cpl_fits_count_extensions(fn) == 0) {
619 cpl_multiframe_append_dataset_from_position(mf,
".", frame, 0,
621 CPL_MULTIFRAME_ID_JOIN);
624 int iext, next = cpl_fits_count_extensions(fn);
625 for (iext = 1; iext <= next; iext++) {
626 cpl_multiframe_append_dataset_from_position(mf,
".", frame, iext,
628 CPL_MULTIFRAME_ID_JOIN);
632 if (!cpl_errorstate_is_equal(state)) {
633 cpl_msg_error(__func__,
"Appending data of \"%s\" for merging failed: %s",
634 fn, cpl_error_get_message());
639 char *outfn = muse_utils_frame_get_basefilename(frame);
640 cpl_errorstate state = cpl_errorstate_get();
641 cpl_multiframe_write(mf, outfn);
642 if (!cpl_errorstate_is_equal(state)) {
643 cpl_msg_error(__func__,
"Writing merged data to \"%s\" failed: %s",
644 outfn, cpl_error_get_message());
646 cpl_frame_set_filename(frame, outfn);
648 cpl_frameset_insert(frames, cpl_frame_duplicate(frame));
651 cpl_multiframe_delete(mf);
652 cpl_frameset_delete(fset);
654 cpl_regex_delete(regex);
655 cpl_regex_delete(nregex);
656 cpl_regex_delete(nregex2);
659 printf(
"\naFrames (trying to remove these):\n");
660 cpl_frameset_dump(aFrames, stdout);
662 printf(
"\nmerged frames:\n");
663 cpl_frameset_dump(frames, stdout);
668 int iframe, nframes = cpl_frameset_get_size(frames);
669 for (iframe = 0; iframe < nframes; iframe++) {
670 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
672 cpl_msg_debug(__func__,
"===== Starting to compare \"%s\" =====",
673 cpl_frame_get_filename(frame));
676 for (iframe2 = 0; iframe2 < cpl_frameset_get_size(aFrames); iframe2++) {
678 cpl_frame *frame2 = cpl_frameset_get_position(aFrames, iframe2);
679 char *fb1 = muse_utils_frame_get_basefilename(frame),
680 *fb2 = muse_utils_frame_get_basefilename(frame2);
681 if (muse_utils_frames_compare_basenames(frame, frame2) == 1) {
682 const char *fn = cpl_frame_get_filename(frame2);
684 cpl_msg_debug(__func__,
"Removing \"%s\" (\"%s\" vs \"%s\").",
688 cpl_frameset_erase_frame(aFrames, frame2);
695 cpl_frameset_join(aFrames, frames);
696 cpl_frameset_delete(frames);
698 printf(
"\nmerged out frames:\n");
699 cpl_frameset_dump(aFrames, stdout);
703 return CPL_ERROR_NONE;
728 cpl_msg_debug(__func__,
"No table found for tag %s and IFU %hhu", aTag,
732 cpl_msg_debug(__func__,
"No table found for tag %s", aTag);
738 const char *fn = cpl_frame_get_filename(frame);
741 if (extension <= 0) {
743 cpl_msg_debug(__func__,
"didn't find a specific extension for IFU %hhu, "
744 "will just use the first one", aIFU);
748 cpl_table *table = cpl_table_load(fn, extension, 0);
749 if (!table || !cpl_table_get_nrow(table)) {
750 cpl_msg_info(__func__,
"loading %s from file \"%s\" (ext %d) failed: %s",
751 aTag, fn, extension, cpl_error_get_message());
752 cpl_frame_delete(frame);
753 cpl_table_delete(table);
756 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
757 cpl_errorstate state = cpl_errorstate_get();
759 char *extname = NULL;
760 if (en && cpl_errorstate_is_equal(state)) {
761 extname = cpl_sprintf(
"[%s]", en);
763 cpl_errorstate_set(state);
764 extname = cpl_sprintf(
"%c",
'\0');
766 cpl_msg_info(__func__,
"loaded %s from file \"%s%s\" (ext %d)", aTag, fn,
769 cpl_propertylist_delete(header);
793 cpl_msg_debug(__func__,
"No propertylist found for tag %s", aTag);
797 const char *filename = cpl_frame_get_filename(frame);
798 cpl_propertylist *pl = cpl_propertylist_load(filename, 0);
800 cpl_msg_info(__func__,
"loading %s from file %s failed: %s", aTag,
801 filename, cpl_error_get_message());
802 cpl_frame_delete(frame);
805 cpl_msg_info(__func__,
"loaded %s from file %s", aTag, filename);
823 {
"lambda", CPL_TYPE_DOUBLE,
"Angstrom",
"%7.2f",
"wavelength", CPL_TRUE},
824 {
"throughput", CPL_TYPE_DOUBLE,
"",
"%.4e",
825 "filter response (in fractions of 1)", CPL_TRUE},
826 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
855 cpl_ensure(aFilterName, CPL_ERROR_NULL_INPUT, NULL);
856 if (!strncasecmp(aFilterName,
"none", 4)) {
857 cpl_msg_debug(__func__,
"No filter wanted (filter \"%s\")", aFilterName);
860 if (!strcmp(aFilterName,
"white")) {
861 cpl_msg_debug(__func__,
"White-light integration wanted (filter \"%s\")",
865 cpl_table_set(table,
"lambda", 0, kMuseNominalLambdaMin - 1e-5);
866 cpl_table_set(table,
"lambda", 1, kMuseNominalLambdaMin);
867 cpl_table_set(table,
"lambda", 2, kMuseNominalLambdaMax);
868 cpl_table_set(table,
"lambda", 3, kMuseNominalLambdaMax - 1e-5);
869 cpl_table_set(table,
"throughput", 0, 0.);
870 cpl_table_set(table,
"throughput", 1, 1.);
871 cpl_table_set(table,
"throughput", 2, 1.);
872 cpl_table_set(table,
"throughput", 3, 0.);
876 MUSE_TAG_FILTER_LIST, 0);
878 cpl_error_set_message(__func__, CPL_ERROR_FILE_NOT_FOUND,
"%s (for filter "
879 "\"%s\") is missing", MUSE_TAG_FILTER_LIST,
885 char *filename = (
char *)cpl_frame_get_filename(frame);
886 int ext = cpl_fits_find_extension(filename, aFilterName);
888 cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND,
"\"%s\" does not "
889 "contain filter \"%s\"", filename, aFilterName);
890 cpl_frame_delete(frame);
894 cpl_table *table = cpl_table_load(filename, ext, 0);
895 if (!table || !cpl_table_get_nrow(table)) {
896 cpl_error_set_message(__func__, cpl_error_get_code(),
"loading filter "
897 "\"%s\" from file \"%s\" (ext %d) failed",
898 aFilterName, filename, ext);
899 cpl_frame_delete(frame);
900 cpl_table_delete(table);
903 cpl_msg_info(__func__,
"loaded filter \"%s\" from file \"%s\" (ext %d)",
904 aFilterName, filename, ext);
935 cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, NULL);
937 char *lampname = NULL;
939 for (n = 1; n <= nlamps; n++) {
940 cpl_errorstate prestate = cpl_errorstate_get();
943 if (!cpl_errorstate_is_equal(prestate)) {
944 cpl_errorstate_set(prestate);
950 if (!strncmp(name,
"CU-LAMP-", 8)) {
953 if (!strcmp(name,
"CU-LAMP3") || !strcmp(name,
"CU-LAMP6")) {
958 }
else if (!strcmp(name,
"CU-LAMP4")) {
962 }
else if (!strcmp(name,
"CU-LAMP5")) {
970 char *temp = lampname;
971 lampname = cpl_sprintf(
"%s%c%s", temp, aSep, name);
974 lampname = cpl_sprintf(
"%s", name);
1002 cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, NULL);
1005 cpl_array *lampnumbers = cpl_array_new(0, CPL_TYPE_INT);
1007 for (n = 1; n <= nlamps; n++) {
1008 cpl_errorstate prestate = cpl_errorstate_get();
1011 if (!cpl_errorstate_is_equal(prestate)) {
1012 cpl_errorstate_set(prestate);
1018 cpl_array_set_size(lampnumbers, cpl_array_get_size(lampnumbers) + 1);
1019 cpl_array_set_int(lampnumbers, cpl_array_get_size(lampnumbers) - 1,
1022 if (cpl_array_get_size(lampnumbers) < 1) {
1023 cpl_array_delete(lampnumbers);
1045 cpl_matrix *kernel = cpl_matrix_new(2*aXHalfwidth+1, 2*aYHalfwidth+1);
1047 cpl_msg_error(__func__,
"Could not create matrix: %s",
1048 cpl_error_get_message());
1053 for (i = -aXHalfwidth; i <= aXHalfwidth; i++) {
1055 for (j = -aYHalfwidth; j <= aYHalfwidth; j++) {
1057 double gauss = 1. / (aSigma*sqrt(2.*CPL_MATH_PI))
1058 * exp(-(i*i + j*j) / (2.*aSigma*aSigma));
1059 cpl_matrix_set(kernel, i+aXHalfwidth, j+aYHalfwidth, gauss);
1064 cpl_matrix_divide_scalar(kernel, sum);
1092 unsigned short aYOrder)
1094 cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, NULL);
1098 int nx = cpl_image_get_size_x(aImage),
1099 ny = cpl_image_get_size_y(aImage);
1100 cpl_matrix *pos = cpl_matrix_new(2, nx * ny);
1101 cpl_vector *val = cpl_vector_new(nx * ny);
1103 for (i = 1; i < nx; i++) {
1104 for (j = 1; j < ny; j++) {
1105 if (cpl_image_is_rejected(aImage, i, j)) {
1108 cpl_matrix_set(pos, 0, np, i);
1109 cpl_matrix_set(pos, 1, np, j);
1111 cpl_vector_set(val, np, cpl_image_get(aImage, i, j, &err));
1117 cpl_matrix_delete(pos);
1118 cpl_vector_delete(val);
1119 cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND,
"No good pixels "
1120 "found in image, polynomial fit cannot be performed!");
1124 cpl_matrix_set_size(pos, 2, np);
1125 cpl_vector_set_size(val, np);
1128 cpl_polynomial *poly = cpl_polynomial_new(2);
1129 const cpl_boolean sym = CPL_FALSE;
1130 const cpl_size mindeg[] = { 0, 0 },
1131 maxdeg[] = { aXOrder, aYOrder };
1132 cpl_error_code rc = cpl_polynomial_fit(poly, pos, &sym, val, NULL, CPL_TRUE,
1134 cpl_matrix_delete(pos);
1135 cpl_vector_delete(val);
1138 cpl_image *fit = NULL;
1139 if (rc == CPL_ERROR_NONE) {
1140 fit = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
1141 cpl_image_fill_polynomial(fit, poly, 1, 1, 1, 1);
1142 if (cpl_image_get_bpm_const(aImage)) {
1143 cpl_image_reject_from_mask(fit, cpl_image_get_bpm_const(aImage));
1146 cpl_polynomial_delete(poly);
1179 int aX2,
int aY2,
double *aX,
double *aY,
1182 cpl_ensure_code(aImage, CPL_ERROR_NULL_INPUT);
1183 cpl_ensure_code(aX || aY, CPL_ERROR_NULL_INPUT);
1185 cpl_image *im = cpl_image_extract(aImage, aX1, aY1, aX2, aY2);
1186 cpl_ensure_code(im, cpl_error_get_code());
1190 bg = cpl_image_get_mean(im);
1192 bg = cpl_image_get_median(im);
1195 CPL_ERROR_ILLEGAL_INPUT);
1197 cpl_image_subtract_scalar(im, bg);
1201 cpl_image *row = cpl_image_collapse_create(im, 0);
1204 int i, n = cpl_image_get_size_x(row);
1205 for (i = 1; i <= n; i++) {
1207 double value = cpl_image_get(row, i, 1, &err);
1214 *aX = w / f + aX1 - 1;
1215 cpl_image_delete(row);
1219 cpl_image *col = cpl_image_collapse_create(im, 1);
1222 int j, n = cpl_image_get_size_y(col);
1223 for (j = 1; j <= n; j++) {
1225 double value = cpl_image_get(col, 1, j, &err);
1232 *aY = w / f + aY1 - 1;
1233 cpl_image_delete(col);
1235 cpl_image_delete(im);
1237 return CPL_ERROR_NONE;
1273 const cpl_vector *aValues,
const cpl_vector *aErrors,
1276 cpl_ensure_code(aPositions && aValues, CPL_ERROR_NULL_INPUT);
1277 cpl_ensure_code(cpl_matrix_get_ncol(aPositions) == 2, CPL_ERROR_ILLEGAL_INPUT);
1278 int npoints = cpl_matrix_get_nrow(aPositions);
1279 cpl_ensure_code(npoints == cpl_vector_get_size(aValues), CPL_ERROR_ILLEGAL_INPUT);
1281 cpl_ensure_code(cpl_vector_get_size(aValues) == cpl_vector_get_size(aErrors),
1282 CPL_ERROR_ILLEGAL_INPUT);
1284 cpl_ensure_code(aX || aY, CPL_ERROR_NULL_INPUT);
1286 const double *values = cpl_vector_get_data_const(aValues);
1287 double xcen = 0., ycen = 0.,
1288 weight = 0., bg = 0.;
1290 bg = cpl_vector_get_mean(aValues);
1292 bg = cpl_vector_get_median_const(aValues);
1295 CPL_ERROR_ILLEGAL_INPUT);
1299 for (i = 0; i < npoints; i++) {
1300 double w = values[i] - bg;
1305 w /= cpl_vector_get(aErrors, i);
1307 xcen += cpl_matrix_get(aPositions, i, 0) * w;
1308 ycen += cpl_matrix_get(aPositions, i, 1) * w;
1320 return CPL_ERROR_NONE;
1348 muse_utils_multigauss(
const double x[],
const double p[],
double *f)
1350 const double xp = x[0];
1351 const cpl_size ncoeffs = p[0],
1353 const double sigma = p[2 + ncoeffs];
1356 for (i = 0; i < npeaks; i++) {
1357 if (p[2 + ncoeffs + 1 + i] == xp) {
1370 for (ic = 0; ic < ncoeffs; ic++) {
1371 *f += p[2 + ic] * pow(xp, ic);
1375 for (ip = 0; ip < npeaks; ip++) {
1376 const double xi = p[3 + ncoeffs + ip],
1377 Ai = p[3 + ncoeffs + npeaks + ip],
1378 exponent = (xi - xp) / sigma;
1379 *f += Ai / CPL_MATH_SQRT2PI / sigma * exp(-0.5 * exponent*exponent);
1382 printf(
"eval at %f --> %f\n", xp, *f);
1384 for (i = 0; i < ncoeffs + 2*npeaks + 3; i++) {
1385 printf(
" [%02d] %f\n", i, p[i]);
1404 muse_utils_dmultigauss(
const double x[],
const double p[],
double f[])
1406 const cpl_size ncoeffs = p[0],
1408 const double sigma = p[2 + ncoeffs];
1410 memset(f, 0,
sizeof(
double) * (ncoeffs + 2*npeaks + 3));
1414 const double xp = x[0];
1418 for (ic = 0; ic < ncoeffs; ic++) {
1419 f[2 + ic] = pow(xp, ic);
1422 f[2 + ncoeffs] = 0.;
1424 for (ip = 0; ip < npeaks; ip++) {
1425 const double xi = p[3 + ncoeffs + ip],
1426 Ai = p[3 + ncoeffs + npeaks + ip],
1427 exponent = (xi - xp) / sigma,
1428 expsq = exponent * exponent,
1429 expfunc = exp(-0.5 * expsq);
1430 f[2 + ncoeffs] -= Ai / CPL_MATH_SQRT2PI / (sigma*sigma)
1431 * (1 - expsq) * expfunc;
1433 f[3 + ncoeffs + ip] = -Ai / CPL_MATH_SQRT2PI / (sigma*sigma*sigma)
1434 * (xi - xp) * expfunc;
1436 f[3 + ncoeffs + npeaks + ip] = 1 / CPL_MATH_SQRT2PI / sigma * expfunc;
1439 printf(
"deval at %f -->\n", xp);
1441 for (i = 0; i < ncoeffs + 2*npeaks + 3; i++) {
1442 printf(
" [%02d] %e %f\n", i, f[i], p[i]);
1503 cpl_vector *aCenter,
double *aSigma,
1504 cpl_vector *aFlux, cpl_vector *aPoly,
1505 double *aMSE,
double *aRedChisq,
1506 cpl_matrix **aCovariance)
1509 *aCovariance = NULL;
1511 cpl_ensure_code(aX && aY && aCenter && aSigma, CPL_ERROR_NULL_INPUT);
1512 cpl_size npoints = cpl_vector_get_size(aX);
1513 cpl_ensure_code(npoints == cpl_bivector_get_size(aY), CPL_ERROR_INCOMPATIBLE_INPUT);
1514 cpl_size npeaks = cpl_vector_get_size(aCenter);
1515 cpl_ensure_code(!aFlux || npeaks == cpl_vector_get_size(aFlux),
1516 CPL_ERROR_INCOMPATIBLE_INPUT);
1517 cpl_size ncoeffs = aPoly ? cpl_vector_get_size(aPoly) : 0,
1520 cpl_ensure_code(!aRedChisq || npoints >= npars, CPL_ERROR_ILLEGAL_INPUT);
1523 cpl_matrix *x = cpl_matrix_wrap(npoints, 1, (
double *)cpl_vector_get_data_const(aX));
1524 const cpl_vector *y = cpl_bivector_get_x_const(aY),
1525 *ye = cpl_bivector_get_y_const(aY);
1527 cpl_vector *p = cpl_vector_new(npars + 2);
1528 int *pflags = cpl_calloc(npars + 2,
sizeof(
int));
1530 cpl_vector_set(p, 0, ncoeffs);
1531 cpl_vector_set(p, 1, npeaks);
1533 for (i = 2; i < npars + 2; i++) {
1537 cpl_array *aflags = cpl_array_wrap_int(pflags, npars + 2);
1538 printf(
"aflags, non-zero means parameter is fitted by cpl_fit_lvmq():\n");
1539 cpl_array_dump(aflags, 0, 1000, stdout);
1541 cpl_array_unwrap(aflags);
1545 for (j = 0, i = 2; j < ncoeffs; j++, i++) {
1546 cpl_vector_set(p, i, cpl_vector_get(aPoly, j));
1549 double sigma = fabs(*aSigma);
1553 cpl_vector_set(p, i++, sigma);
1555 for (j = 0; j < npeaks; j++, i++) {
1556 cpl_vector_set(p, i, cpl_vector_get(aCenter, j));
1559 for (j = 0; j < npeaks; j++, i++) {
1561 cpl_vector_set(p, i, cpl_vector_get(aFlux, j));
1563 cpl_vector_set(p, i, 1.);
1567 printf(
"input parameters p and their pflags:\n");
1568 for (j = 0; j < cpl_vector_get_size(p); j++) {
1569 printf(
" [%02d] %f %s\n", j, cpl_vector_get(p, j),
1570 pflags[j] ?
"\tfitted" :
"constant");
1573 cpl_matrix *covariance = NULL;
1574 cpl_error_code rc = cpl_fit_lvmq(x, NULL, y, ye, p, pflags,
1575 muse_utils_multigauss, muse_utils_dmultigauss,
1576 CPL_FIT_LVMQ_TOLERANCE, CPL_FIT_LVMQ_COUNT,
1577 CPL_FIT_LVMQ_MAXITER, aMSE, aRedChisq,
1579 cpl_matrix_unwrap(x);
1582 printf(
"output parameters vector p (%e, %e):\n",
1583 aMSE ? sqrt(*aMSE) : 0.0, aRedChisq ? *aRedChisq : 0.0);
1584 cpl_vector_dump(p, stdout);
1588 for (j = 0, i = 2; j < ncoeffs; j++, i++) {
1589 cpl_vector_set(aPoly, j, cpl_vector_get(p, i));
1594 *aSigma = fabs(cpl_vector_get(p, i++));
1595 for (j = 0; j < npeaks; j++, i++) {
1596 cpl_vector_set(aCenter, j, cpl_vector_get(p, i));
1600 for (j = 0; j < npeaks; j++, i++) {
1601 cpl_vector_set(aFlux, j, cpl_vector_get(p, i));
1607 *aCovariance = cpl_matrix_extract(covariance, 2, 2, 1, 1,
1608 cpl_matrix_get_nrow(covariance) - 2,
1609 cpl_matrix_get_ncol(covariance) - 2);
1611 cpl_matrix_delete(covariance);
1612 cpl_vector_delete(p);
1616 #if MOFFAT_USE_MUSE_OPTIMIZE
1620 const cpl_matrix *positions;
1621 const cpl_vector *values;
1622 const cpl_vector *errors;
1638 static cpl_error_code
1639 muse_moffat_2d_optfunc(
void *aData, cpl_array *aParams, cpl_array *aResiduals)
1641 const cpl_matrix *pos = ((fitdata_t *)aData)->positions;
1642 const cpl_vector *val = ((fitdata_t *)aData)->values,
1643 *err = ((fitdata_t *)aData)->errors;
1645 const double *p = cpl_array_get_data_double_const(aParams);
1646 double *residuals = cpl_array_get_data_double(aResiduals);
1647 int i, npoints = cpl_vector_get_size(val);
1648 for (i = 0; i < npoints; i++) {
1649 double xterm = (cpl_matrix_get(pos, i, 0) - p[2]) / p[4],
1650 yterm = (cpl_matrix_get(pos, i, 1) - p[3]) / p[5],
1651 crossterm = 2 * p[7] * xterm * yterm,
1652 base = 1 + (xterm*xterm + crossterm + yterm*yterm) / (1 + p[7]*p[7]),
1653 moffat = p[0] + p[1] * (p[6] - 1)
1654 / (CPL_MATH_PI * p[4]*p[5] * sqrt(1 - p[7]*p[7]))
1657 residuals[i] = cpl_vector_get(val, i) - moffat;
1659 residuals[i] /= cpl_vector_get(err, i);
1661 return CPL_ERROR_NONE;
1680 muse_moffat_2d_function(
const double xy[],
const double p[],
double *f)
1682 double xterm = (xy[0] - p[2]) / p[4],
1683 yterm = (xy[1] - p[3]) / p[5],
1684 crossterm = 2 * p[7] * xterm * yterm,
1685 rhoterm = 1. - p[7]*p[7],
1686 base = 1. + (xterm*xterm + crossterm + yterm*yterm) / rhoterm;
1687 *f = p[0] + p[1] * (p[6] - 1.) / (CPL_MATH_PI * p[4]*p[5] * sqrt(rhoterm))
1708 muse_moffat_2d_derivative(
const double xy[],
const double p[],
double f[])
1710 double xterm = (xy[0] - p[2]) / p[4],
1711 yterm = (xy[1] - p[3]) / p[5],
1712 crossterm = 2 * p[7] * xterm * yterm,
1713 rhoterm = 1. - p[7]*p[7],
1714 base = 1. + (xterm*xterm + crossterm + yterm*yterm) / (rhoterm);
1716 f[1] = (p[6] - 1.) / (CPL_MATH_PI * p[4]*p[5] * sqrt(rhoterm))
1718 f[2] = 2 * p[1] * p[6]*(p[6] - 1.)
1719 / (CPL_MATH_PI * p[4]*p[4] * p[5] * pow(rhoterm, 3./2.))
1720 * (xterm + p[7] * yterm) * pow(base, -p[6]-1.);
1721 f[3] = 2 * p[1] * p[6]*(p[6] - 1.)
1722 / (CPL_MATH_PI * p[4] * p[5]*p[5] * pow(rhoterm, 3./2.))
1723 * (yterm + p[7] * xterm) * pow(base, -p[6]-1.);
1724 f[4] = p[1] * (p[6] - 1.)
1725 / (CPL_MATH_PI * p[4]*p[4] * p[5] * sqrt(rhoterm))
1726 * (-pow(base, -p[6]) + 2 * p[6] / (rhoterm) * pow(base, -p[6]-1.)
1727 * (xterm*xterm + 0.5*crossterm));
1728 f[5] = p[1] * (p[6] - 1.)
1729 / (CPL_MATH_PI * p[4] * p[5]*p[5] * sqrt(rhoterm))
1730 * (-pow(base, -p[6]) + 2 * p[6] / (rhoterm) * pow(base, -p[6]-1.)
1731 * (yterm*yterm + 0.5*crossterm));
1732 f[6] = p[1] / (CPL_MATH_PI * p[4]*p[5] * sqrt(rhoterm))
1733 * pow(base, -p[6]) * (1. + (p[6] - 1.) * log(base));
1734 f[7] = p[1] * (p[6] - 1.)
1735 / (CPL_MATH_PI * p[4]*p[5] * pow(rhoterm, 3./2.))
1736 * (p[7] * pow(base, -p[6])
1737 - 2. * p[6] * pow(base, -p[6]-1.)
1738 * (xterm*yterm * (1 + 2*p[7]*p[7] / rhoterm)
1739 + p[7] / rhoterm * (xterm*xterm + yterm*yterm) ));
1823 const cpl_vector *aValues,
const cpl_vector *aErrors,
1824 cpl_array *aParams, cpl_array *aPErrors,
1825 const cpl_array *aPFlags,
1826 double *aRMS,
double *aRedChisq)
1830 return cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
1831 "Missing input positions.");
1834 return cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
1835 "Missing input values / errors.");
1837 if (cpl_matrix_get_ncol(aPositions) != 2) {
1838 return cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
1839 "Input positions are not for two-dimensional data.");
1841 if (cpl_vector_get_size(aValues) != cpl_matrix_get_nrow(aPositions)) {
1842 return cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
1843 "Input positions and values data must have same size.");
1845 if (aErrors && (cpl_vector_get_size(aValues) != cpl_vector_get_size(aErrors))) {
1846 return cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
1847 "Input vectors must have same size.");
1850 return cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
1851 "Missing input parameters array.");
1853 if (cpl_array_get_type(aParams) != CPL_TYPE_DOUBLE) {
1854 return cpl_error_set_message(__func__, CPL_ERROR_INVALID_TYPE,
1855 "Parameters array should be CPL_TYPE_DOUBLE.");
1857 if (aPErrors && (cpl_array_get_type(aPErrors) != CPL_TYPE_DOUBLE)) {
1858 return cpl_error_set_message(__func__, CPL_ERROR_INVALID_TYPE,
1859 "Parameters error array should be CPL_TYPE_DOUBLE.");
1861 if (aPFlags && (cpl_array_get_type(aPFlags) != CPL_TYPE_INT)) {
1862 return cpl_error_set_message(__func__, CPL_ERROR_INVALID_TYPE,
1863 "Parameters error array should be CPL_TYPE_INT.");
1865 if ((aPErrors || aRedChisq) && !aErrors) {
1866 return cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND,
1867 "Missing input parameters errors.");
1869 int npoints = cpl_matrix_get_nrow(aPositions);
1872 return cpl_error_set_message(__func__, CPL_ERROR_SINGULAR_MATRIX,
1873 "%d are not enough points to fit a Moffat profile.",
1877 int pflags[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
1880 int idx, nparam = 0;
1881 for (idx = 0; idx < 8; idx++) {
1882 int err, flag = cpl_array_get_int(aPFlags, idx, &err);
1888 cpl_array_get_double(aParams, idx, &err);
1890 return cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
1891 "Missing frozen value for parameter %d.", idx);
1896 return cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
1897 "No free parameters");
1907 double bg = cpl_array_get_double(aParams, 0, &invalid);
1909 bg = cpl_vector_get_median_const(aValues);
1914 double volguess = (cpl_vector_get_mean(aValues) - bg) * npoints;
1915 if (fabs(volguess) < FLT_EPSILON) {
1917 cpl_array_set_double(aParams, 0, bg);
1918 cpl_array_set_double(aParams, 1, 0.);
1919 cpl_array_set_invalid(aParams, 2);
1920 cpl_array_set_invalid(aParams, 3);
1921 cpl_array_set_invalid(aParams, 4);
1922 cpl_array_set_invalid(aParams, 5);
1923 cpl_array_set_double(aParams, 6, 1.);
1925 printf(
"flat Moffat:\n");
1926 cpl_array_dump(aParams, 0, 10, stdout);
1929 return CPL_ERROR_NONE;
1938 double xc = cpl_array_get_double(aParams, 2, &invalid);
1942 double yc = cpl_array_get_double(aParams, 3, &invalid);
1951 double beta = cpl_array_get_double(aParams, 6, &invalid);
1961 double alphay, alphax = cpl_array_get_double(aParams, 4, &invalid);
1963 alphay = cpl_array_get_double(aParams, 5, &invalid);
1965 double amplitude = 0.;
1966 if (volguess > 0.) {
1967 amplitude = cpl_vector_get_max(aValues) - bg;
1969 amplitude = cpl_vector_get_min(aValues) - bg;
1971 double halfpeak = amplitude / 2. + bg,
1972 limit = amplitude * 0.01;
1973 const double *values = cpl_vector_get_data_const(aValues);
1974 cpl_vector *vradius = cpl_vector_new(1);
1978 for (i = 0; i < npoints; i++) {
1979 if (values[i] > halfpeak - limit && values[i] < halfpeak + limit) {
1980 cpl_vector_set_size(vradius, nfound + 1);
1981 double radius = sqrt(pow(cpl_matrix_get(aPositions, i, 0) - xcen, 2)
1982 + pow(cpl_matrix_get(aPositions, i, 1) - ycen, 2));
1984 printf(
"radius(%d, %d) = %f\n", i, nfound+1, radius);
1986 cpl_vector_set(vradius, nfound++, radius);
1993 printf(
"found %d points (limit = %f)\n", nfound, limit / 2);
1995 }
while (nfound < 3 && isfinite(limit));
1996 if (!isfinite(limit)) {
1999 alphax = alphay = 1.;
2004 alphax = alphay = cpl_vector_get_mean(vradius) / sqrt(pow(2., 1./beta)-1);
2006 printf(
"estimated alphas = %f from radius %f\n", alphax, cpl_vector_get_mean(vradius));
2010 cpl_vector_delete(vradius);
2015 alphay = cpl_array_get_double(aParams, 5, &invalid);
2023 double volume = cpl_array_get_double(aParams, 1, &invalid);
2034 double rho = cpl_array_get_double(aParams, 7, &invalid);
2040 cpl_vector *params = cpl_vector_new(8);
2041 cpl_vector_set(params, 0, bg);
2042 cpl_vector_set(params, 1, volume);
2043 cpl_vector_set(params, 2, xc);
2044 cpl_vector_set(params, 3, yc);
2045 cpl_vector_set(params, 4, alphax);
2046 cpl_vector_set(params, 5, alphay);
2047 cpl_vector_set(params, 6, beta);
2048 cpl_vector_set(params, 7, rho);
2050 printf(
"initial guess values for Moffat (vol %e):\n", (cpl_vector_get_mean(aValues) - bg) * npoints);
2051 cpl_vector_dump(params, stdout);
2054 cpl_matrix *covariance = NULL;
2056 cpl_error_code rc = CPL_ERROR_NONE;
2057 #if MOFFAT_USE_MUSE_OPTIMIZE
2059 fitdata.positions = aPositions;
2060 fitdata.values = aValues;
2061 fitdata.errors = aErrors;
2062 cpl_array *optparams = cpl_array_wrap_double(cpl_vector_get_data(params), 8);
2064 muse_moffat_2d_optfunc, NULL);
2065 cpl_array_unwrap(optparams);
2067 cpl_errorstate prestate = cpl_errorstate_get();
2068 rc = cpl_fit_lvmq(aPositions, NULL, aValues, aErrors, params, pflags,
2069 muse_moffat_2d_function, muse_moffat_2d_derivative,
2070 CPL_FIT_LVMQ_TOLERANCE, CPL_FIT_LVMQ_COUNT,
2071 CPL_FIT_LVMQ_MAXITER, aRMS,
2072 aErrors ? aRedChisq : NULL, aErrors ? &covariance : NULL);
2075 *aRMS = sqrt(*aRMS);
2079 printf(
"Moffat fit (rc=%d, %s):\n", rc, cpl_error_get_message());
2080 cpl_vector_dump(params, stdout);
2083 if (rc == CPL_ERROR_NONE || rc == CPL_ERROR_SINGULAR_MATRIX ||
2084 rc == CPL_ERROR_CONTINUE) {
2090 if (isfinite(cpl_vector_get(params, 0)) &&
2091 isfinite(cpl_vector_get(params, 1)) &&
2092 isfinite(cpl_vector_get(params, 2)) &&
2093 isfinite(cpl_vector_get(params, 3)) &&
2094 isfinite(cpl_vector_get(params, 4)) &&
2095 isfinite(cpl_vector_get(params, 5)) &&
2096 isfinite(cpl_vector_get(params, 6)) &&
2097 isfinite(cpl_vector_get(params, 7))) {
2099 rc = CPL_ERROR_NONE;
2100 cpl_errorstate_set(prestate);
2105 cpl_array_set_double(aParams, 0, cpl_vector_get(params, 0));
2106 cpl_array_set_double(aParams, 1, cpl_vector_get(params, 1));
2107 cpl_array_set_double(aParams, 2, cpl_vector_get(params, 2));
2108 cpl_array_set_double(aParams, 3, cpl_vector_get(params, 3));
2109 cpl_array_set_double(aParams, 4, fabs(cpl_vector_get(params, 4)));
2110 cpl_array_set_double(aParams, 5, fabs(cpl_vector_get(params, 5)));
2111 cpl_array_set_double(aParams, 6, cpl_vector_get(params, 6));
2112 cpl_array_set_double(aParams, 7, cpl_vector_get(params, 7));
2114 if (aErrors && covariance) {
2116 for (idx = 0; idx < 8; idx++) {
2117 if (pflags[idx] && aPErrors) {
2118 cpl_array_set_double(aPErrors, idx,
2119 sqrt(cpl_matrix_get(covariance, idx, idx)));
2127 cpl_matrix_delete(covariance);
2128 cpl_vector_delete(params);
2179 cpl_vector *aErr, cpl_table *aExtra,
2180 const unsigned int aOrder,
const double aRSigma,
2181 double *aMSE,
double *aChiSq)
2190 cpl_ensure(aPos && aVal, CPL_ERROR_NULL_INPUT, NULL);
2191 cpl_ensure(cpl_matrix_get_ncol(aPos) == cpl_vector_get_size(aVal),
2192 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
2194 cpl_ensure(cpl_vector_get_size(aVal) == cpl_vector_get_size(aErr),
2195 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
2198 cpl_ensure(cpl_vector_get_size(aVal) == cpl_table_get_nrow(aExtra),
2199 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
2204 for (idx = 0; idx < cpl_vector_get_size(aVal); idx++) {
2206 if (isfinite(cpl_vector_get(aVal, idx))) {
2210 if (cpl_vector_get_size(aVal) == 1) {
2211 cpl_msg_warning(__func__,
"Input vector only contained non-finite elements!");
2215 cpl_matrix_erase_columns(aPos, idx, 1);
2222 cpl_table_erase_window(aExtra, idx, 1);
2228 int ndim = cpl_matrix_get_nrow(aPos);
2229 cpl_polynomial *fit = cpl_polynomial_new(ndim);
2230 int large_residuals = 1;
2231 while (large_residuals > 0) {
2232 const cpl_boolean sym = CPL_FALSE;
2233 cpl_size *mindeg = cpl_calloc(ndim,
sizeof(cpl_size)),
2234 *maxdeg = cpl_malloc(ndim *
sizeof(cpl_size));
2236 for (i = 0; i < ndim; i++) {
2239 cpl_error_code rc = cpl_polynomial_fit(fit, aPos, &sym, aVal, NULL,
2240 CPL_FALSE, mindeg, maxdeg);
2243 const cpl_size coeff = 0;
2244 if (rc != CPL_ERROR_NONE || !isfinite(cpl_polynomial_get_coeff(fit, &coeff))) {
2246 cpl_errorstate prestate = cpl_errorstate_get();
2248 printf(
"%s: output polynomial:\n", __func__);
2249 cpl_polynomial_dump(fit, stdout);
2250 printf(
"%s: positions and values that we tried to fit:\n", __func__);
2251 cpl_matrix_dump(aPos, stdout);
2252 cpl_vector_dump(aVal, stdout);
2255 cpl_polynomial_delete(fit);
2257 if (!cpl_errorstate_is_equal(prestate)) {
2258 cpl_errorstate_set(prestate);
2264 cpl_vector *res = cpl_vector_new(cpl_vector_get_size(aVal));
2265 cpl_vector_fill_polynomial_fit_residual(res, aVal, NULL, fit, aPos, aChiSq);
2266 double rms = sqrt(cpl_vector_product(res, res) / cpl_vector_get_size(res));
2272 printf(
"%s: polynomial fit (RMS %g chisq %g aRSigma %f -> limit %g):\n",
2273 __func__, rms, aChiSq ? *aChiSq : 0., aRSigma, aRSigma * rms);
2274 cpl_polynomial_dump(fit, stdout);
2276 char *title = cpl_sprintf(
"set title \"%s: RMS %g\"\n"
2277 "unset key\n", __func__, rms);
2278 cpl_plot_vector(title,
"",
"", res);
2282 large_residuals = 0;
2283 for (i = 0; i < cpl_vector_get_size(res); i++) {
2285 if (fabs(cpl_vector_get(res, i)) < (aRSigma * rms)) {
2292 cpl_msg_debug(__func__,
"residual %f RMS %f aRSigma %f -> limit %f",
2293 cpl_vector_get(res, i), rms, aRSigma, aRSigma * rms);
2296 if (cpl_vector_get_size(res) == 1) {
2297 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
"tried to "
2298 "remove the last vector/matrix element when "
2299 "checking fit residuals (residual %g RMS %g "
2300 "aRSigma %f -> limit %g)", cpl_vector_get(res, i),
2301 rms, aRSigma, aRSigma * rms);
2302 cpl_polynomial_delete(fit);
2304 rms = sqrt(DBL_MAX);
2308 large_residuals = 0;
2313 cpl_matrix_erase_columns(aPos, i, 1);
2320 cpl_table_erase_window(aExtra, i, 1);
2325 cpl_vector_delete(res);
2383 double aLambda,
double aHalfWidth,
2385 cpl_array *aResults, cpl_array *aErrors)
2387 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, 0.);
2390 cpl_table_unselect_all(aPixtable->
table);
2391 cpl_table_or_selected_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA,
2392 CPL_NOT_LESS_THAN, aLambda - aHalfWidth);
2393 cpl_table_and_selected_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA,
2394 CPL_NOT_GREATER_THAN, aLambda + aHalfWidth);
2395 cpl_size nsel = cpl_table_count_selected(aPixtable->
table);
2396 cpl_ensure(nsel > 0, CPL_ERROR_DATA_NOT_FOUND, 0.);
2400 cpl_errorstate state = cpl_errorstate_get();
2402 cpl_table_unselect_all(aPixtable->
table);
2403 if (!cpl_errorstate_is_equal(state)) {
2405 cpl_table_delete(spec);
2406 cpl_error_set(__func__, cpl_error_get_code());
2411 cpl_size nbins = cpl_table_get_nrow(spec);
2413 cpl_table_power_column(spec,
"stat", 0.5);
2414 cpl_table_name_column(spec,
"stat",
"error");
2415 cpl_table_set_column_unit(spec,
"error",
2416 cpl_table_get_column_unit(spec,
"data"));
2418 cpl_table_save(spec, NULL, NULL,
"spec.fits", CPL_IO_CREATE);
2421 cpl_vector *pos = cpl_vector_wrap(nbins, cpl_table_get_data_double(spec,
"lambda")),
2422 *val = cpl_vector_wrap(nbins, cpl_table_get_data_double(spec,
"data")),
2423 *err = cpl_vector_wrap(nbins, cpl_table_get_data_double(spec,
"error"));
2424 double xc, xerr = 2 * aHalfWidth,
2425 sigma, area, bglevel, mse;
2426 cpl_matrix *covariance;
2427 cpl_error_code rc = cpl_vector_fit_gaussian(pos, NULL, val, err, CPL_FIT_ALL,
2428 &xc, &sigma, &area, &bglevel,
2429 &mse, NULL, &covariance);
2430 cpl_vector_unwrap(pos);
2431 cpl_vector_unwrap(val);
2432 cpl_vector_unwrap(err);
2433 cpl_table_delete(spec);
2434 if (rc == CPL_ERROR_CONTINUE) {
2436 xerr = sqrt(sigma * sigma / area);
2437 }
else if (rc == CPL_ERROR_SINGULAR_MATRIX || !covariance) {
2438 xerr = sqrt(sigma * sigma / area);
2440 xerr = sqrt(cpl_matrix_get(covariance, 0, 0));
2442 cpl_msg_debug(__func__,
"covariance matrix:");
2443 cpl_matrix_dump(covariance, stdout);
2447 if (aResults && cpl_array_get_type(aResults) == CPL_TYPE_DOUBLE) {
2448 cpl_array_set_size(aResults, 4);
2449 cpl_array_set_double(aResults, 0, xc);
2450 cpl_array_set_double(aResults, 1, sigma);
2451 cpl_array_set_double(aResults, 2, area);
2452 cpl_array_set_double(aResults, 3, bglevel);
2454 if (aErrors && cpl_array_get_type(aErrors) == CPL_TYPE_DOUBLE) {
2455 cpl_array_set_size(aErrors, 4);
2456 cpl_array_set_double(aErrors, 0, xerr);
2457 if (rc != CPL_ERROR_NONE || !covariance) {
2458 cpl_array_fill_window_invalid(aErrors, 1, 3);
2460 cpl_array_set_double(aErrors, 1, sqrt(cpl_matrix_get(covariance, 1, 1)));
2461 cpl_array_set_double(aErrors, 2, sqrt(cpl_matrix_get(covariance, 2, 2)));
2462 cpl_array_set_double(aErrors, 3, sqrt(cpl_matrix_get(covariance, 3, 3)));
2465 cpl_matrix_delete(covariance);
2466 cpl_msg_debug(__func__,
"Gaussian fit (%s): %f +/- %f Angstrom, %f, %f, %f "
2467 "(RMS %f)", rc != CPL_ERROR_NONE ? cpl_error_get_message() :
"",
2468 xc, xerr, bglevel, area, sigma, sqrt(mse));
2490 const char *aKeyword,
const char *aString)
2492 cpl_ensure_code(aH1 && aH2 && aKeyword && aString, CPL_ERROR_NULL_INPUT);
2493 const char *hin = cpl_propertylist_get_string(aH1, aKeyword);
2494 cpl_ensure_code(hin, CPL_ERROR_ILLEGAL_INPUT);
2495 char *hstring = cpl_sprintf(
"%s (%s)", hin, aString);
2496 cpl_error_code rc = cpl_propertylist_update_string(aH2, aKeyword, hstring);
2531 const char *aExtData,
const char *aExtDQ,
2532 const char *aExtStat)
2534 cpl_ensure_code(aHeader && aClass2 && aExtData, CPL_ERROR_NULL_INPUT);
2535 cpl_ensure_code(!strcmp(aClass2,
"DATA") || !strcmp(aClass2,
"ERROR") ||
2536 !strcmp(aClass2,
"QUALITY"), CPL_ERROR_ILLEGAL_INPUT);
2539 #define ESO_HDU_HEADERS_REGEXP "HDU(CLASS|CLAS1|CLAS2|CLAS3|DOC|VERS)$" \
2540 "|^SCIDATA$|^QUAL(DATA|MASK)$|^ERRDATA$"
2541 cpl_propertylist_erase_regexp(aHeader, ESO_HDU_HEADERS_REGEXP, 0);
2543 if (cpl_propertylist_has(aHeader,
"EXTNAME")) {
2544 cpl_propertylist_insert_after_string(aHeader,
"EXTNAME",
"HDUCLASS",
"ESO");
2546 cpl_propertylist_append_string(aHeader,
"HDUCLASS",
"ESO");
2548 cpl_propertylist_set_comment(aHeader,
"HDUCLASS",
"class name (ESO format)");
2549 cpl_propertylist_insert_after_string(aHeader,
"HDUCLASS",
"HDUDOC",
"DICD");
2550 cpl_propertylist_set_comment(aHeader,
"HDUDOC",
"document with class description");
2551 cpl_propertylist_insert_after_string(aHeader,
"HDUDOC",
"HDUVERS",
2553 cpl_propertylist_set_comment(aHeader,
"HDUVERS",
2554 "version number (according to spec v2.5.1)");
2555 cpl_propertylist_insert_after_string(aHeader,
"HDUVERS",
"HDUCLAS1",
"IMAGE");
2556 cpl_propertylist_set_comment(aHeader,
"HDUCLAS1",
"Image data format");
2557 cpl_propertylist_insert_after_string(aHeader,
"HDUCLAS1",
"HDUCLAS2", aClass2);
2558 if (!strcmp(aClass2,
"DATA")) {
2559 cpl_propertylist_set_comment(aHeader,
"HDUCLAS2",
2560 "this extension contains the data itself");
2563 cpl_propertylist_insert_after_string(aHeader,
"HDUCLAS2",
"QUALDATA", aExtDQ);
2566 cpl_propertylist_insert_after_string(aHeader,
"HDUCLAS2",
"ERRDATA", aExtStat);
2568 }
else if (!strcmp(aClass2,
"ERROR")) {
2569 cpl_propertylist_set_comment(aHeader,
"HDUCLAS2",
"this extension contains variance");
2570 cpl_propertylist_insert_after_string(aHeader,
"HDUCLAS2",
"HDUCLAS3",
"MSE");
2571 cpl_propertylist_set_comment(aHeader,
"HDUCLAS3",
2572 "the extension contains variances (sigma**2)");
2573 cpl_propertylist_insert_after_string(aHeader,
"HDUCLAS3",
"SCIDATA", aExtData);
2575 cpl_propertylist_insert_after_string(aHeader,
"SCIDATA",
"QUALDATA", aExtDQ);
2578 cpl_propertylist_set_comment(aHeader,
"HDUCLAS2",
2579 "this extension contains bad pixel mask");
2580 cpl_propertylist_insert_after_string(aHeader,
"HDUCLAS2",
"HDUCLAS3",
"FLAG32BIT");
2581 cpl_propertylist_set_comment(aHeader,
"HDUCLAS3",
"extension contains 32bit"
2582 " Euro3D bad pixel information");
2584 cpl_propertylist_insert_after_long(aHeader,
"HDUCLAS3",
"QUALMASK", 0xFFFFFFFF);
2585 cpl_propertylist_set_comment(aHeader,
"QUALMASK",
"all non-zero values are bad");
2586 cpl_propertylist_insert_after_string(aHeader,
"QUALMASK",
"SCIDATA", aExtData);
2588 cpl_propertylist_insert_after_string(aHeader,
"SCIDATA",
"ERRDATA", aExtStat);
2592 if (cpl_propertylist_has(aHeader,
"SCIDATA")) {
2593 cpl_propertylist_set_comment(aHeader,
"SCIDATA",
"pointer to the data extension");
2595 if (cpl_propertylist_has(aHeader,
"ERRDATA")) {
2596 cpl_propertylist_set_comment(aHeader,
"ERRDATA",
"pointer to the variance extension");
2598 if (cpl_propertylist_has(aHeader,
"QUALDATA")) {
2599 cpl_propertylist_set_comment(aHeader,
"QUALDATA",
2600 "pointer to the bad pixel mask extension");
2603 return CPL_ERROR_NONE;
2623 char *exe = getenv(
"MUSE_DEBUG_MEMORY_PROGRAM");
2628 printf(
"=== %s ===\n", aMarker);
2631 if (strlen(exe) > 0) {
2632 snprintf(command, 999,
2633 "ps -C %s -o comm,start_time,pid,tid,pcpu,stat,rss,size,vsize",
2637 snprintf(command, 999,
2638 "ps -o comm,start_time,pid,tid,pcpu,stat,rss,size,vsize");
2642 int rc = system(command);
2643 UNUSED_ARGUMENT(rc);
const muse_cpltable_def muse_filtertable_def[]
MUSE filter table definition.
cpl_boolean muse_pfits_has_ifu(const cpl_propertylist *aHeaders, unsigned char aIFU)
Find out the whether this header related to a certain IFU.
const char * muse_pfits_get_extname(const cpl_propertylist *aHeaders)
find out the extension name
int muse_pfits_get_read_id(const cpl_propertylist *aHeaders)
find out the readout mode id
int muse_utils_get_extension_for_ifu(const char *aFilename, unsigned char aIFU)
Return extension number that corresponds to this IFU/channel number.
unsigned char muse_utils_get_ifu(const cpl_propertylist *aHeaders)
Find out the IFU/channel from which this header originated.
double muse_utils_pixtable_fit_line_gaussian(muse_pixtable *aPixtable, double aLambda, double aHalfWidth, double aBinSize, cpl_array *aResults, cpl_array *aErrors)
Fit a 1D Gaussian to a given wavelength range in a pixel table.
int muse_pfits_get_shut_status(const cpl_propertylist *aHeaders, int aShutter)
query the status of one shutter
muse_utils_centroid_type
Background handling when computing centroids.
cpl_error_code muse_cpl_optimize_lvmq(void *aData, cpl_array *aPar, int aSize, muse_cpl_evaluate_func *aFunction, muse_cpl_optimize_control_t *aCtrl)
Minimize a function with the Levenberg-Marquardt algorithm.
void muse_utils_memory_dump(const char *aMarker)
Display the current memory usage of the given program.
const char * muse_pfits_get_dateobs(const cpl_propertylist *aHeaders)
find out the date of observations
cpl_table * table
The pixel table.
int muse_pfits_get_lampnum(const cpl_propertylist *aHeaders)
query the number of lamps installed
cpl_error_code muse_utils_set_hduclass(cpl_propertylist *aHeader, const char *aClass2, const char *aExtData, const char *aExtDQ, const char *aExtStat)
Set HDU headers for the ESO FITS data format.
cpl_table * muse_table_load_filter(muse_processing *aProcessing, const char *aFilterName)
Load a table for a given filter name.
cpl_table * muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
Create an empty table according to the specified definition.
const char * muse_get_license(void)
Get the pipeline copyright and license.
int muse_pfits_get_biny(const cpl_propertylist *aHeaders)
find out the binning factor in y direction
Structure definition of MUSE pixel table.
const char * muse_pfits_get_lamp_name(const cpl_propertylist *aHeaders, int aLamp)
query the name of one lamp
cpl_error_code muse_cplvector_erase_element(cpl_vector *aVector, int aElement)
delete the given element from the input vector
cpl_error_code muse_utils_fit_moffat_2d(const cpl_matrix *aPositions, const cpl_vector *aValues, const cpl_vector *aErrors, cpl_array *aParams, cpl_array *aPErrors, const cpl_array *aPFlags, double *aRMS, double *aRedChisq)
Fit a 2D Moffat function to a given set of data.
const char * muse_pfits_get_pipefile(const cpl_propertylist *aHeaders)
find out the pipefile
cpl_polynomial * muse_utils_iterate_fit_polynomial(cpl_matrix *aPos, cpl_vector *aVal, cpl_vector *aErr, cpl_table *aExtra, const unsigned int aOrder, const double aRSigma, double *aMSE, double *aChiSq)
Iterate a polynomial fit.
const char * muse_pfits_get_read_name(const cpl_propertylist *aHeaders)
find out the readout mode name
cpl_frameset * muse_frameset_sort_raw_other(const cpl_frameset *aFrames, int aIndex, const char *aDateObs, cpl_boolean aSequence)
Create a new frameset containing all relevant raw frames first then all other frames.
void muse_processing_append_used(muse_processing *aProcessing, cpl_frame *aFrame, cpl_frame_group aGroup, int aDuplicate)
Add a frame to the set of used frames.
cpl_error_code muse_utils_fit_multigauss_1d(const cpl_vector *aX, const cpl_bivector *aY, cpl_vector *aCenter, double *aSigma, cpl_vector *aFlux, cpl_vector *aPoly, double *aMSE, double *aRedChisq, cpl_matrix **aCovariance)
Carry out a multi-Gaussian fit of data in a vector.
char * muse_utils_header_get_lamp_names(cpl_propertylist *aHeader, char aSep)
Concatenate names of all active calibration lamps.
const char * muse_pfits_get_chip_id(const cpl_propertylist *aHeaders)
find out the chip id
int muse_pfits_get_binx(const cpl_propertylist *aHeaders)
find out the binning factor in x direction
cpl_array * muse_utils_header_get_lamp_numbers(cpl_propertylist *aHeader)
List numbers of all active calibration lamps.
cpl_image * muse_utils_image_fit_polynomial(const cpl_image *aImage, unsigned short aXOrder, unsigned short aYOrder)
Create a smooth version of a 2D image by fitting it with a 2D polynomial.
int muse_pfits_get_lamp_status(const cpl_propertylist *aHeaders, int aLamp)
query the status of one lamp
cpl_table * muse_table_load(muse_processing *aProcessing, const char *aTag, unsigned char aIFU)
load a table according to its tag and IFU/channel number
cpl_error_code muse_utils_image_get_centroid_window(cpl_image *aImage, int aX1, int aY1, int aX2, int aY2, double *aX, double *aY, muse_utils_centroid_type aBgType)
Compute centroid over an image window, optionally marginalizing over the background.
Definition of a cpl table structure.
cpl_propertylist * muse_propertylist_load(muse_processing *aProcessing, const char *aTag)
load a propertylist according to its tag
cpl_matrix * muse_matrix_new_gaussian_2d(int aXHalfwidth, int aYHalfwidth, double aSigma)
Create a matrix that contains a normalized 2D Gaussian.
cpl_table * muse_resampling_spectrum(muse_pixtable *aPixtable, double aBinwidth)
Resample the selected pixels of a pixel table into a spectrum.
cpl_frameset * muse_frameset_check_raw(const cpl_frameset *aFrames, const cpl_array *aTags, unsigned char aIFU)
return frameset containing good raw input data
cpl_frameset * muse_frameset_find(const cpl_frameset *aFrames, const char *aTag, unsigned char aIFU, cpl_boolean aInvert)
return frameset containing data from an IFU/channel with a certain tag
const char * muse_pfits_get_chip_name(const cpl_propertylist *aHeaders)
find out the chip name
cpl_frame * muse_frameset_find_master(const cpl_frameset *aFrames, const char *aTag, unsigned char aIFU)
find the master frame according to its CCD number and tag
cpl_error_code muse_utils_copy_modified_header(cpl_propertylist *aH1, cpl_propertylist *aH2, const char *aKeyword, const char *aString)
Copy a modified header keyword from one header to another.
cpl_error_code muse_utils_get_centroid(const cpl_matrix *aPositions, const cpl_vector *aValues, const cpl_vector *aErrors, double *aX, double *aY, muse_utils_centroid_type aBgType)
Compute centroid of a two-dimensional dataset.
cpl_frameset * muse_frameset_find_tags(const cpl_frameset *aFrames, const cpl_array *aTags, unsigned char aIFU, cpl_boolean aInvert)
return frameset containing data from an IFU/channel with the given tag(s)