00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027
00028
00029
00030 #if HAVE_DRAND48
00031 #define _XOPEN_SOURCE
00032 #endif
00033 #include <cpl.h>
00034 #include <cpl_multiframe.h>
00035 #include <float.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <strings.h>
00039 #ifdef HAVE_GETTIMEOFDAY
00040 #include <sys/time.h>
00041 #endif
00042
00043 #include "muse_utils.h"
00044 #include "muse_instrument.h"
00045
00046 #include "muse_cplwrappers.h"
00047 #include "muse_pfits.h"
00048 #include "muse_resampling.h"
00049 #include "muse_tracing.h"
00050 #include "muse_wcs.h"
00051
00052
00053
00054
00055 #define MOFFAT_USE_MUSE_OPTIMIZE 0
00056
00057 #if MOFFAT_USE_MUSE_OPTIMIZE
00058 #include "muse_optimize.h"
00059 #endif
00060
00061
00067
00068
00071
00080
00081 const char *
00082 muse_get_license(void)
00083 {
00084 return cpl_get_license(PACKAGE_NAME, "2005, 2015");
00085 }
00086
00087
00095
00096 unsigned char
00097 muse_utils_get_ifu(const cpl_propertylist *aHeaders)
00098 {
00099 unsigned char n;
00100 for (n = 1; n <= kMuseNumIFUs; n++) {
00101 if (muse_pfits_has_ifu(aHeaders, n)) {
00102 return n;
00103 }
00104 }
00105 return 0;
00106 }
00107
00108
00115
00116 int
00117 muse_utils_get_extension_for_ifu(const char *aFilename, unsigned char aIFU)
00118 {
00119 cpl_errorstate prestate = cpl_errorstate_get();
00120 int i, next = cpl_fits_count_extensions(aFilename);
00121 for (i = 0; i <= next; i++) {
00122 cpl_propertylist *properties = cpl_propertylist_load(aFilename, i);
00123 if (muse_pfits_has_ifu(properties, aIFU)) {
00124 cpl_propertylist_delete(properties);
00125 return i;
00126 }
00127 cpl_propertylist_delete(properties);
00128 }
00129 cpl_errorstate_set(prestate);
00130 return -1;
00131 }
00132
00133
00157
00158 cpl_frameset *
00159 muse_frameset_find(const cpl_frameset *aFrames, const char *aTag,
00160 unsigned char aIFU, cpl_boolean aInvert)
00161 {
00162 cpl_ensure(aFrames, CPL_ERROR_NULL_INPUT, NULL);
00163 cpl_frameset *newFrames = cpl_frameset_new();
00164
00165
00166 cpl_size iframe, nframes = cpl_frameset_get_size(aFrames);
00167 for (iframe = 0; iframe < nframes; iframe++) {
00168 const cpl_frame *frame = cpl_frameset_get_position_const(aFrames, iframe);
00169 const char *fn = cpl_frame_get_filename(frame),
00170 *tag = cpl_frame_get_tag(frame);
00171
00172
00173
00174 cpl_boolean matched = !aInvert && (!aTag || (aTag && !strcmp(tag, aTag))),
00175 unmatched = aInvert
00176 && ((aTag && !tag) || (aTag && strcmp(tag, aTag)));
00177 if (matched || unmatched) {
00178
00179
00180 cpl_errorstate prestate = cpl_errorstate_get();
00181 int extension = muse_utils_get_extension_for_ifu(fn, aIFU);
00182
00183
00184 if (extension == -1) {
00185 extension = 0;
00186 cpl_errorstate_set(prestate);
00187 }
00188 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
00189 if (!header) {
00190
00191
00192 continue;
00193 }
00194 unsigned char ifu = muse_utils_get_ifu(header);
00195 prestate = cpl_errorstate_get();
00196 const char *pipefile = muse_pfits_get_pipefile(header);
00197 if (!cpl_errorstate_is_equal(prestate)) {
00198
00199 cpl_errorstate_set(prestate);
00200 }
00201 if (ifu == aIFU) {
00202
00203 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
00204 } else if (ifu == 0 && !pipefile) {
00205
00206
00207 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
00208 } else if (aIFU == 0) {
00209
00210 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
00211 } else if (aTag && (!strncmp(aTag, MUSE_TAG_GEOMETRY_TABLE,
00212 strlen(MUSE_TAG_GEOMETRY_TABLE) + 1) ||
00213 !strncmp(aTag, MUSE_TAG_TWILIGHT_CUBE,
00214 strlen(MUSE_TAG_TWILIGHT_CUBE) + 1))) {
00215
00216
00217 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
00218 } else {
00219
00220 #if 0
00221 cpl_msg_debug(__func__, "not added %s / %s / %d", fn,
00222 cpl_frame_get_tag(frame), ifu);
00223 #endif
00224 }
00225 cpl_propertylist_delete(header);
00226 }
00227 }
00228
00229 return newFrames;
00230 }
00231
00232
00250
00251 cpl_frameset *
00252 muse_frameset_find_tags(const cpl_frameset *aFrames, const cpl_array *aTags,
00253 unsigned char aIFU, cpl_boolean aInvert)
00254 {
00255 cpl_ensure(aFrames && aTags, CPL_ERROR_NULL_INPUT, NULL);
00256 cpl_ensure(cpl_array_get_type(aTags) == CPL_TYPE_STRING,
00257 CPL_ERROR_ILLEGAL_INPUT, NULL);
00258
00259 cpl_frameset *outframes = cpl_frameset_new();
00260 cpl_size itag, ntags = cpl_array_get_size(aTags);
00261 for (itag = 0; itag < ntags; itag++) {
00262 const char *tag = cpl_array_get_string(aTags, itag);
00263 cpl_frameset *frames = muse_frameset_find(aFrames, tag, aIFU, aInvert);
00264 cpl_frameset_join(outframes, frames);
00265 cpl_frameset_delete(frames);
00266 }
00267 return outframes;
00268 }
00269
00270
00281
00282 cpl_frameset *
00283 muse_frameset_check_raw(const cpl_frameset *aFrames, const cpl_array *aTags,
00284 unsigned char aIFU)
00285 {
00286 cpl_frameset *foundFrames = muse_frameset_find_tags(aFrames, aTags, aIFU,
00287 CPL_FALSE);
00288 cpl_frameset *newFrames = cpl_frameset_new();
00289
00290
00291 cpl_size iframe, nframes = cpl_frameset_get_size(foundFrames);
00292 cpl_msg_debug(__func__, "Determine properties of all %"CPL_SIZE_FORMAT
00293 " raw frames of IFU %hhu", nframes, aIFU);
00294 int binx = -1, biny = -1, readid = -1;
00295 char *fn = NULL, *readname = NULL, *chipname = NULL, *chipid = NULL;
00296 for (iframe = 0; iframe < nframes; iframe++) {
00297 const cpl_frame *frame = cpl_frameset_get_position_const(foundFrames, iframe);
00298
00299
00300 const char *fn2 = cpl_frame_get_filename(frame);
00301 if (!fn) {
00302 fn = cpl_strdup(fn2);
00303 }
00304 cpl_propertylist *header = cpl_propertylist_load(fn2, 0);
00305 if (!header) {
00306 cpl_msg_warning(__func__, "Cannot read primary FITS header of file "
00307 "\"%s\"!", fn2);
00308 continue;
00309 }
00310 int extension = muse_utils_get_extension_for_ifu(fn2, aIFU);
00311 if (extension > 0) {
00312 cpl_propertylist *exthead = cpl_propertylist_load(fn2, extension);
00313 cpl_propertylist_append(header, exthead);
00314 cpl_propertylist_delete(exthead);
00315 }
00316 cpl_boolean isOK = CPL_TRUE;
00317 if (binx < 0) {
00318 binx = muse_pfits_get_binx(header);
00319 }
00320 if (biny < 0) {
00321 biny = muse_pfits_get_biny(header);
00322 }
00323 if (!readname) {
00324 readname = cpl_strdup(muse_pfits_get_read_name(header));
00325 }
00326 if (readid < 0) {
00327 readid = muse_pfits_get_read_id(header);
00328 }
00329 if (!chipname) {
00330 chipname = cpl_strdup(muse_pfits_get_chip_name(header));
00331 }
00332 if (!chipid) {
00333 chipid = cpl_strdup(muse_pfits_get_chip_id(header));
00334 }
00335 int binx2 = muse_pfits_get_binx(header),
00336 biny2 = muse_pfits_get_biny(header),
00337 readid2 = muse_pfits_get_read_id(header);
00338 const char *chipname2 = muse_pfits_get_chip_name(header),
00339 *chipid2 = muse_pfits_get_chip_id(header);
00340 if (binx2 != binx) {
00341 cpl_msg_warning(__func__, "File \"%s\" (IFU %hhu) was taken with a different"
00342 " x-binning factor (reference \"%s\", %d instead of %d)!",
00343 fn2, aIFU, fn, binx2, binx);
00344 isOK = 0;
00345 }
00346 if (biny2 != biny) {
00347 cpl_msg_warning(__func__, "File \"%s\" (IFU %hhu) was taken with a different"
00348 " y-binning factor (reference \"%s\", %d instead of %d)!",
00349 fn2, aIFU, fn, biny2, biny);
00350 isOK = 0;
00351 }
00352 if (readid2 != readid) {
00353 cpl_msg_warning(__func__, "File \"%s\" (IFU %hhu) was taken with a different"
00354 " read-out mode (reference \"%s\", %d/%s instead of %d/%s)!",
00355 fn2, aIFU, fn, readid2, muse_pfits_get_read_name(header),
00356 readid, readname);
00357 isOK = 0;
00358 }
00359 if (!chipname2 || !chipid2 ||
00360 strcmp(chipname, chipname2) || strcmp(chipid, chipid2)) {
00361 cpl_msg_warning(__func__, "File \"%s\" (IFU %hhu) has a different chip "
00362 "setup (reference \"%s\", name %s vs %s, id %s vs %s)",
00363 fn2, aIFU, fn, chipname2, chipname, chipid2, chipid);
00364 isOK = 0;
00365 }
00366
00367 if (!cpl_frame_get_tag(frame) ||
00368 !strncmp(cpl_frame_get_tag(frame), MUSE_TAG_EMPTY, 1) ) {
00369
00370
00371 cpl_msg_warning(__func__, "File \"%s\" (IFU %hhu) is not tagged!", fn2,
00372 aIFU);
00373 }
00374 cpl_propertylist_delete(header);
00375 if (isOK) {
00376 cpl_frameset_insert(newFrames, cpl_frame_duplicate(frame));
00377 }
00378 }
00379 cpl_free(fn);
00380 cpl_free(readname);
00381 cpl_free(chipname);
00382 cpl_free(chipid);
00383 cpl_frameset_delete(foundFrames);
00384
00385 return newFrames;
00386 }
00387
00388
00415
00416 cpl_frameset *
00417 muse_frameset_sort_raw_other(const cpl_frameset *aFrames, int aIndex,
00418 const char *aDateObs, cpl_boolean aSequence)
00419 {
00420 cpl_ensure(aFrames, CPL_ERROR_NULL_INPUT, NULL);
00421
00422 cpl_frameset *fraw = cpl_frameset_new(),
00423 *fillum = cpl_frameset_new(),
00424 *fother = cpl_frameset_new();
00425 int iraw = 0,
00426 nillum = 0;
00427 cpl_size iframe, nframes = cpl_frameset_get_size(aFrames);
00428 for (iframe = 0; iframe < nframes; iframe++) {
00429 const cpl_frame *frame = cpl_frameset_get_position_const(aFrames, iframe);
00430 if (cpl_frame_get_group(frame) == CPL_FRAME_GROUP_RAW) {
00431 const char *tag = cpl_frame_get_tag(frame);
00432 if (!tag || (tag && strncmp(tag, "ILLUM", 6))) {
00433
00434
00435 int datematch = 1;
00436 if (aDateObs) {
00437 cpl_propertylist *header
00438 = cpl_propertylist_load(cpl_frame_get_filename(frame), 0);
00439 const char *dateobs = muse_pfits_get_dateobs(header);
00440 datematch = dateobs && !strncmp(aDateObs, dateobs, strlen(aDateObs));
00441 cpl_propertylist_delete(header);
00442 }
00443 if ((aIndex < 0 && datematch) || aIndex == iraw || aSequence) {
00444 cpl_frameset_insert(fraw, cpl_frame_duplicate(frame));
00445 }
00446 iraw++;
00447 } else {
00448
00449
00450 if (!nillum) {
00451 cpl_frameset_insert(fillum, cpl_frame_duplicate(frame));
00452 }
00453 nillum++;
00454 }
00455 } else {
00456 cpl_frameset_insert(fother, cpl_frame_duplicate(frame));
00457 }
00458 }
00459 #if 0
00460 printf("incoming frames (index=%d, DATE-OBS=%s):\n", aIndex, aDateObs);
00461 cpl_frameset_dump(aFrames, stdout);
00462 fflush(stdout);
00463 printf("=============================================================\n"
00464 "raw frames:\n");
00465 cpl_frameset_dump(fraw, stdout);
00466 printf("illum frames:\n");
00467 cpl_frameset_dump(fillum, stdout);
00468 printf("-------------------------------------------------------------\n"
00469 "other frames:\n");
00470 cpl_frameset_dump(fother, stdout);
00471 printf("^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n");
00472 fflush(stdout);
00473 #endif
00474
00475
00476 cpl_frameset_join(fraw, fillum);
00477 cpl_frameset_join(fraw, fother);
00478 cpl_frameset_delete(fother);
00479 cpl_frameset_delete(fillum);
00480 #if 0
00481 printf("=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=_=\n"
00482 "all sorted frames:\n");
00483 cpl_frameset_dump(fraw, stdout);
00484 printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
00485 fflush(stdout);
00486 #endif
00487
00488 return fraw;
00489 }
00490
00491
00502
00503 cpl_frame *
00504 muse_frameset_find_master(const cpl_frameset *aFrames, const char *aTag,
00505 unsigned char aIFU)
00506 {
00507 cpl_frameset *frames = muse_frameset_find(aFrames, aTag, aIFU, CPL_FALSE);
00508 cpl_frame *frame = NULL;
00509 if (cpl_frameset_count_tags(frames, aTag) == 1) {
00510 frame = cpl_frame_duplicate(cpl_frameset_get_position_const(frames, 0));
00511 }
00512 cpl_frameset_delete(frames);
00513 return frame;
00514 }
00515
00516
00517
00518
00519 static char *
00520 muse_utils_frame_get_basefilename(const cpl_frame *aFrame)
00521 {
00522 char *filename = cpl_strdup(cpl_frame_get_filename(aFrame)),
00523 *end = strstr(filename, ".fits");
00524 if (end) {
00525 *end = '\0';
00526 }
00527 end = strrchr(filename, '-');
00528 if (end) {
00529 *end = '\0';
00530 }
00531 return filename;
00532 }
00533
00534
00535
00536 static int
00537 muse_utils_frames_compare_basenames(const cpl_frame *aF1, const cpl_frame *aF2)
00538 {
00539 cpl_ensure(aF1 && aF2, CPL_ERROR_NULL_INPUT, -1);
00540 cpl_ensure(cpl_frame_get_filename(aF1) && cpl_frame_get_filename(aF2),
00541 CPL_ERROR_DATA_NOT_FOUND, -1);
00542 char *fn1 = muse_utils_frame_get_basefilename(aF1),
00543 *fn2 = muse_utils_frame_get_basefilename(aF2);
00544 int cmp = strcmp(fn1, fn2);
00545 cpl_free(fn1);
00546 cpl_free(fn2);
00547 return cmp == 0 ? 1 : 0;
00548 }
00549
00550
00551
00552 static int
00553 muse_utils_frame_compare(const cpl_frame *aF1, const cpl_frame *aF2)
00554 {
00555 const char *fn1 = cpl_frame_get_filename(aF1),
00556 *fn2 = cpl_frame_get_filename(aF2);
00557 int cmp = strcmp(fn1, fn2);
00558 return (cmp < 0) ? -1 : (cmp > 0) ? 1 : 0;
00559 }
00560
00561
00586
00587 cpl_error_code
00588 muse_utils_frameset_merge_frames(cpl_frameset *aFrames, cpl_boolean aDelete)
00589 {
00590 cpl_ensure_code(aFrames, CPL_ERROR_NULL_INPUT);
00591
00592 cpl_ensure_code(cpl_frameset_get_size(aFrames) > 0, CPL_ERROR_ILLEGAL_INPUT);
00593 #if 0
00594 printf("final out frames:\n");
00595 cpl_frameset_dump(aFrames, stdout);
00596 fflush(stdout);
00597 #endif
00598
00599
00600
00601 #define EXTKEYS1 MUSE_WCS_KEYS"|(ESO DET (CHIP|OUT[1-9]*) |ESO QC|ESO DRS)"
00602 #define EXTKEYS2 MUSE_WCS_KEYS"|^B(UNIT|SCALE|ZERO)"
00603 cpl_regex *regex = cpl_regex_new(EXTKEYS1, TRUE, CPL_REGEX_EXTENDED),
00604 *nregex = cpl_regex_new(EXTKEYS1, FALSE, CPL_REGEX_EXTENDED),
00605 *nregex2 = cpl_regex_new(EXTKEYS1"|"EXTKEYS2, FALSE,
00606 CPL_REGEX_EXTENDED);
00607
00608
00609 cpl_frameset *frames = cpl_frameset_new();
00610
00611 cpl_size ilabel;
00612 cpl_size nlabels = 0;
00613 cpl_size *labels = cpl_frameset_labelise(aFrames,
00614 muse_utils_frames_compare_basenames,
00615 &nlabels);
00616 for (ilabel = 0; ilabel < nlabels; ilabel++) {
00617 cpl_frameset *fset = cpl_frameset_extract(aFrames, labels, ilabel);
00618
00619
00620 cpl_frameset_sort(fset, muse_utils_frame_compare);
00621
00622 cpl_frame *frame = cpl_frameset_get_position(fset, 0);
00623 const char *tag = cpl_frame_get_tag(frame);
00624
00625
00626
00627 if (strncmp(tag, "PIXTABLE_", 9) == 0) {
00628 cpl_frameset_delete(fset);
00629 continue;
00630 }
00631
00632 int n = cpl_frameset_get_size(fset);
00633 if (n <= 1) {
00634 cpl_msg_warning(__func__, "Nothing to merge for tag %s (%d frames)!",
00635 tag, n);
00636 cpl_frameset_delete(fset);
00637 continue;
00638 }
00639
00640 cpl_multiframe *mf = cpl_multiframe_new(frame, "", regex);
00641 if (!mf) {
00642 cpl_frameset_delete(fset);
00643 continue;
00644 }
00645
00646
00647 int i;
00648 for (i = 0; i < n; i++) {
00649 frame = cpl_frameset_get_position(fset, i);
00650 const char *fn = cpl_frame_get_filename(frame);
00651 cpl_msg_debug(__func__, "Merging \"%s\".", fn);
00652
00653 int extdata = cpl_fits_find_extension(fn, EXTNAME_DATA),
00654 extdq = cpl_fits_find_extension(fn, EXTNAME_DQ),
00655 extstat = cpl_fits_find_extension(fn, EXTNAME_STAT);
00656 cpl_errorstate state = cpl_errorstate_get();
00657 if (extdata > 0 && extdq > 0 && extstat > 0) {
00658
00659 const char *extnames[] = { EXTNAME_DATA, EXTNAME_DQ, EXTNAME_STAT },
00660 *updkeys[] = { "SCIDATA", "ERRDATA", "QUALDATA", NULL };
00661 const cpl_regex *filters[] = { nregex, nregex, nregex };
00662 cpl_multiframe_append_datagroup(mf, ".", frame, 3, extnames, filters,
00663 NULL, updkeys, CPL_MULTIFRAME_ID_JOIN);
00664 } else if (cpl_fits_count_extensions(fn) == 0) {
00665
00666
00667 cpl_multiframe_append_dataset_from_position(mf, ".", frame, 0,
00668 nregex2, NULL,
00669 CPL_MULTIFRAME_ID_JOIN);
00670 } else {
00671
00672 int iext, next = cpl_fits_count_extensions(fn);
00673 for (iext = 1; iext <= next; iext++) {
00674 cpl_multiframe_append_dataset_from_position(mf, ".", frame, iext,
00675 nregex, NULL,
00676 CPL_MULTIFRAME_ID_JOIN);
00677 }
00678 }
00679
00680 if (!cpl_errorstate_is_equal(state)) {
00681 cpl_msg_error(__func__, "Appending data of \"%s\" for merging failed: %s",
00682 fn, cpl_error_get_message());
00683 }
00684 }
00685
00686
00687 char *basefn = muse_utils_frame_get_basefilename(frame),
00688 *outfn = cpl_sprintf("%s.fits", basefn);
00689 cpl_free(basefn);
00690 cpl_errorstate state = cpl_errorstate_get();
00691 cpl_multiframe_write(mf, outfn);
00692 if (!cpl_errorstate_is_equal(state)) {
00693 cpl_msg_error(__func__, "Writing merged data to \"%s\" failed: %s",
00694 outfn, cpl_error_get_message());
00695 } else {
00696 cpl_frame_set_filename(frame, outfn);
00697
00698
00699 cpl_frame_set_group(frame, CPL_FRAME_GROUP_PRODUCT);
00700
00701 cpl_frameset_insert(frames, cpl_frame_duplicate(frame));
00702 }
00703 cpl_free(outfn);
00704 cpl_multiframe_delete(mf);
00705 cpl_frameset_delete(fset);
00706 }
00707 cpl_regex_delete(regex);
00708 cpl_regex_delete(nregex);
00709 cpl_regex_delete(nregex2);
00710 cpl_free(labels);
00711 #if 0
00712 printf("\naFrames (trying to remove these):\n");
00713 cpl_frameset_dump(aFrames, stdout);
00714 fflush(stdout);
00715 printf("\nmerged frames:\n");
00716 cpl_frameset_dump(frames, stdout);
00717 fflush(stdout);
00718 #endif
00719
00720
00721 int iframe, nframes = cpl_frameset_get_size(frames);
00722 for (iframe = 0; aDelete == CPL_TRUE && iframe < nframes; iframe++) {
00723 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
00724 #if 1
00725 cpl_msg_debug(__func__, "===== Starting to compare \"%s\" =====",
00726 cpl_frame_get_filename(frame));
00727 #endif
00728 int iframe2;
00729 for (iframe2 = 0; iframe2 < cpl_frameset_get_size(aFrames); iframe2++) {
00730
00731 cpl_frame *frame2 = cpl_frameset_get_position(aFrames, iframe2);
00732 if (muse_utils_frames_compare_basenames(frame, frame2) == 1) {
00733 const char *fn = cpl_frame_get_filename(frame2);
00734 #if 1
00735 char *fb1 = muse_utils_frame_get_basefilename(frame),
00736 *fb2 = muse_utils_frame_get_basefilename(frame2);
00737 cpl_msg_debug(__func__, "Removing \"%s\" (\"%s\" vs \"%s\").",
00738 fn, fb1, fb2);
00739 cpl_free(fb1);
00740 cpl_free(fb2);
00741 #endif
00742 remove(fn);
00743 cpl_frameset_erase_frame(aFrames, frame2);
00744 iframe2--;
00745 }
00746 }
00747 }
00748 cpl_frameset_join(aFrames, frames);
00749 cpl_frameset_delete(frames);
00750 #if 0
00751 printf("\nmerged out frames:\n");
00752 cpl_frameset_dump(aFrames, stdout);
00753 fflush(stdout);
00754 #endif
00755 return CPL_ERROR_NONE;
00756 }
00757
00758
00771
00772 cpl_table *
00773 muse_table_load(muse_processing *aProcessing, const char *aTag,
00774 unsigned char aIFU)
00775 {
00776 cpl_frame *frame = muse_frameset_find_master(aProcessing->inframes, aTag,
00777 aIFU);
00778 if (!frame) {
00779 if (aIFU > 0) {
00780 cpl_msg_debug(__func__, "No table found for tag %s and IFU %hhu", aTag,
00781 aIFU);
00782 } else {
00783
00784 cpl_msg_debug(__func__, "No table found for tag %s", aTag);
00785 }
00786 return NULL;
00787 }
00788
00789
00790 const char *fn = cpl_frame_get_filename(frame);
00791 int extension = muse_utils_get_extension_for_ifu(fn, aIFU);
00792
00793 if (extension <= 0) {
00794 if (aIFU > 0) {
00795 cpl_msg_debug(__func__, "didn't find a specific extension for IFU %hhu, "
00796 "will just use the first one", aIFU);
00797 }
00798 extension = 1;
00799 }
00800 cpl_table *table = cpl_table_load(fn, extension, 1);
00801 if (!table || !cpl_table_get_nrow(table)) {
00802 cpl_msg_info(__func__, "loading %s from file \"%s\" (ext %d) failed: %s",
00803 aTag, fn, extension, cpl_error_get_message());
00804 cpl_frame_delete(frame);
00805 cpl_table_delete(table);
00806 return NULL;
00807 }
00808 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
00809 cpl_errorstate state = cpl_errorstate_get();
00810 const char *en = muse_pfits_get_extname(header);
00811 char *extname = NULL;
00812 if (en && cpl_errorstate_is_equal(state)) {
00813 extname = cpl_sprintf("[%s]", en);
00814 } else {
00815 cpl_errorstate_set(state);
00816 extname = cpl_sprintf("%c", '\0');
00817 }
00818 cpl_msg_info(__func__, "loaded %s from file \"%s%s\" (ext %d)", aTag, fn,
00819 extname, extension);
00820 cpl_free(extname);
00821 cpl_propertylist_delete(header);
00822
00823
00824 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_CALIB, 0);
00825
00826 return table;
00827 }
00828
00829
00839
00840 cpl_propertylist *
00841 muse_propertylist_load(muse_processing *aProcessing, const char *aTag)
00842 {
00843 cpl_frame *frame = muse_frameset_find_master(aProcessing->inframes, aTag, 0);
00844 if (!frame) {
00845 cpl_msg_debug(__func__, "No propertylist found for tag %s", aTag);
00846 return NULL;
00847 }
00848
00849 const char *filename = cpl_frame_get_filename(frame);
00850 cpl_propertylist *pl = cpl_propertylist_load(filename, 0);
00851 if (!pl) {
00852 cpl_msg_info(__func__, "loading %s from file %s failed: %s", aTag,
00853 filename, cpl_error_get_message());
00854 cpl_frame_delete(frame);
00855 return NULL;
00856 }
00857 cpl_msg_info(__func__, "loaded %s from file \"%s\"", aTag, filename);
00858
00859
00860 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_CALIB, 0);
00861
00862 return pl;
00863 }
00864
00865
00873
00874 const muse_cpltable_def muse_filtertable_def[] = {
00875 { "lambda", CPL_TYPE_DOUBLE, "Angstrom", "%7.2f", "wavelength", CPL_TRUE},
00876 { "throughput", CPL_TYPE_DOUBLE, "", "%.4e",
00877 "filter response (in fractions of 1)", CPL_TRUE},
00878 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
00879 };
00880
00881
00903
00904 cpl_table *
00905 muse_table_load_filter(muse_processing *aProcessing, const char *aFilterName)
00906 {
00907 cpl_ensure(aFilterName, CPL_ERROR_NULL_INPUT, NULL);
00908 if (!strncasecmp(aFilterName, "none", 4)) {
00909 cpl_msg_debug(__func__, "No filter wanted (filter \"%s\")", aFilterName);
00910 return NULL;
00911 }
00912 if (!strcmp(aFilterName, "white")) {
00913 cpl_msg_debug(__func__, "White-light integration wanted (filter \"%s\")",
00914 aFilterName);
00915
00916 cpl_table *table = muse_cpltable_new(muse_filtertable_def, 4);
00917 cpl_table_set(table, "lambda", 0, kMuseNominalLambdaMin - 1e-5);
00918 cpl_table_set(table, "lambda", 1, kMuseNominalLambdaMin);
00919 cpl_table_set(table, "lambda", 2, kMuseNominalLambdaMax);
00920 cpl_table_set(table, "lambda", 3, kMuseNominalLambdaMax - 1e-5);
00921 cpl_table_set(table, "throughput", 0, 0.);
00922 cpl_table_set(table, "throughput", 1, 1.);
00923 cpl_table_set(table, "throughput", 2, 1.);
00924 cpl_table_set(table, "throughput", 3, 0.);
00925 return table;
00926 }
00927 cpl_frame *frame = muse_frameset_find_master(aProcessing->inframes,
00928 MUSE_TAG_FILTER_LIST, 0);
00929 if (!frame) {
00930 cpl_error_set_message(__func__, CPL_ERROR_FILE_NOT_FOUND, "%s (for filter "
00931 "\"%s\") is missing", MUSE_TAG_FILTER_LIST,
00932 aFilterName);
00933 return NULL;
00934 }
00935
00936
00937 char *filename = (char *)cpl_frame_get_filename(frame);
00938 int ext = cpl_fits_find_extension(filename, aFilterName);
00939 if (ext <= 0) {
00940 cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND, "\"%s\" does not "
00941 "contain filter \"%s\"", filename, aFilterName);
00942 cpl_frame_delete(frame);
00943 return NULL;
00944 }
00945
00946 cpl_table *table = cpl_table_load(filename, ext, 1);
00947 if (!table || !cpl_table_get_nrow(table)) {
00948 cpl_error_set_message(__func__, cpl_error_get_code(), "loading filter "
00949 "\"%s\" from file \"%s\" (ext %d) failed",
00950 aFilterName, filename, ext);
00951 cpl_frame_delete(frame);
00952 cpl_table_delete(table);
00953 return NULL;
00954 }
00955 cpl_msg_info(__func__, "loaded filter \"%s\" from file \"%s\" (ext %d)",
00956 aFilterName, filename, ext);
00957
00958
00959 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_CALIB, 0);
00960 return table;
00961 }
00962
00963
00983
00984 char *
00985 muse_utils_header_get_lamp_names(cpl_propertylist *aHeader, char aSep)
00986 {
00987 cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, NULL);
00988
00989 char *lampname = NULL;
00990 int n, nlamps = muse_pfits_get_lampnum(aHeader);
00991 for (n = 1; n <= nlamps; n++) {
00992 cpl_errorstate prestate = cpl_errorstate_get();
00993 int st1 = muse_pfits_get_lamp_status(aHeader, n),
00994 st2 = muse_pfits_get_shut_status(aHeader, n);
00995 if (!cpl_errorstate_is_equal(prestate)) {
00996 cpl_errorstate_set(prestate);
00997 }
00998 if (!st1 || !st2) {
00999 continue;
01000 }
01001 char *name = (char *)muse_pfits_get_lamp_name(aHeader, n);
01002 if (!strncmp(name, "CU-LAMP-", 8)) {
01003 name += 8;
01004 }
01005 if (!strcmp(name, "CU-LAMP3") || !strcmp(name, "CU-LAMP6")) {
01006
01007 name[0] = 'N';
01008 name[1] = 'e';
01009 name[2] = '\0';
01010 } else if (!strcmp(name, "CU-LAMP4")) {
01011 name[0] = 'X';
01012 name[1] = 'e';
01013 name[2] = '\0';
01014 } else if (!strcmp(name, "CU-LAMP5")) {
01015 name[0] = 'H';
01016 name[1] = 'g';
01017 name[2] = 'C';
01018 name[3] = 'd';
01019 name[4] = '\0';
01020 }
01021 if (lampname) {
01022 char *temp = lampname;
01023 lampname = cpl_sprintf("%s%c%s", temp, aSep, name);
01024 cpl_free(temp);
01025 } else {
01026 lampname = cpl_sprintf("%s", name);
01027 }
01028 }
01029 return lampname;
01030 }
01031
01032
01050
01051 cpl_array *
01052 muse_utils_header_get_lamp_numbers(cpl_propertylist *aHeader)
01053 {
01054 cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, NULL);
01055
01056
01057 cpl_array *lampnumbers = cpl_array_new(0, CPL_TYPE_INT);
01058 int n, nlamps = muse_pfits_get_lampnum(aHeader);
01059 for (n = 1; n <= nlamps; n++) {
01060 cpl_errorstate prestate = cpl_errorstate_get();
01061 int st1 = muse_pfits_get_lamp_status(aHeader, n),
01062 st2 = muse_pfits_get_shut_status(aHeader, n);
01063 if (!cpl_errorstate_is_equal(prestate)) {
01064 cpl_errorstate_set(prestate);
01065 }
01066 if (!st1 || !st2) {
01067 continue;
01068 }
01069
01070 cpl_array_set_size(lampnumbers, cpl_array_get_size(lampnumbers) + 1);
01071 cpl_array_set_int(lampnumbers, cpl_array_get_size(lampnumbers) - 1,
01072 n);
01073 }
01074 if (cpl_array_get_size(lampnumbers) < 1) {
01075 cpl_array_delete(lampnumbers);
01076 lampnumbers = NULL;
01077 }
01078 return lampnumbers;
01079 }
01080
01081
01093
01094 cpl_matrix *
01095 muse_matrix_new_gaussian_2d(int aXHalfwidth, int aYHalfwidth, double aSigma)
01096 {
01097 cpl_matrix *kernel = cpl_matrix_new(2*aXHalfwidth+1, 2*aYHalfwidth+1);
01098 if (!kernel) {
01099 cpl_msg_error(__func__, "Could not create matrix: %s",
01100 cpl_error_get_message());
01101 return NULL;
01102 }
01103 double sum = 0.;
01104 int i;
01105 for (i = -aXHalfwidth; i <= aXHalfwidth; i++) {
01106 int j;
01107 for (j = -aYHalfwidth; j <= aYHalfwidth; j++) {
01108
01109 double gauss = 1. / (aSigma*sqrt(2.*CPL_MATH_PI))
01110 * exp(-(i*i + j*j) / (2.*aSigma*aSigma));
01111 cpl_matrix_set(kernel, i+aXHalfwidth, j+aYHalfwidth, gauss);
01112 sum += gauss;
01113 }
01114 }
01115
01116 cpl_matrix_divide_scalar(kernel, sum);
01117
01118 return kernel;
01119 }
01120
01121
01141
01142 cpl_image *
01143 muse_utils_image_fit_polynomial(const cpl_image *aImage, unsigned short aXOrder,
01144 unsigned short aYOrder)
01145 {
01146 cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, NULL);
01147
01148
01149
01150 int nx = cpl_image_get_size_x(aImage),
01151 ny = cpl_image_get_size_y(aImage);
01152 cpl_matrix *pos = cpl_matrix_new(2, nx * ny);
01153 cpl_vector *val = cpl_vector_new(nx * ny);
01154 int i, j, np = 0;
01155 for (i = 1; i < nx; i++) {
01156 for (j = 1; j < ny; j++) {
01157 if (cpl_image_is_rejected(aImage, i, j)) {
01158 continue;
01159 }
01160 cpl_matrix_set(pos, 0, np, i);
01161 cpl_matrix_set(pos, 1, np, j);
01162 int err;
01163 cpl_vector_set(val, np, cpl_image_get(aImage, i, j, &err));
01164 np++;
01165 }
01166 }
01167
01168 if (!np) {
01169 cpl_matrix_delete(pos);
01170 cpl_vector_delete(val);
01171 cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND, "No good pixels "
01172 "found in image, polynomial fit cannot be performed!");
01173 return NULL;
01174 }
01175
01176 cpl_matrix_set_size(pos, 2, np);
01177 cpl_vector_set_size(val, np);
01178
01179
01180 cpl_polynomial *poly = cpl_polynomial_new(2);
01181 const cpl_boolean sym = CPL_FALSE;
01182 const cpl_size mindeg[] = { 0, 0 },
01183 maxdeg[] = { aXOrder, aYOrder };
01184 cpl_error_code rc = cpl_polynomial_fit(poly, pos, &sym, val, NULL, CPL_TRUE,
01185 mindeg, maxdeg);
01186 cpl_matrix_delete(pos);
01187 cpl_vector_delete(val);
01188
01189
01190 cpl_image *fit = NULL;
01191 if (rc == CPL_ERROR_NONE) {
01192 fit = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
01193 cpl_image_fill_polynomial(fit, poly, 1, 1, 1, 1);
01194 if (cpl_image_get_bpm_const(aImage)) {
01195 cpl_image_reject_from_mask(fit, cpl_image_get_bpm_const(aImage));
01196 }
01197 }
01198 cpl_polynomial_delete(poly);
01199 return fit;
01200 }
01201
01202
01228
01229 cpl_error_code
01230 muse_utils_image_get_centroid_window(cpl_image *aImage, int aX1, int aY1,
01231 int aX2, int aY2, double *aX, double *aY,
01232 muse_utils_centroid_type aBgType)
01233 {
01234 cpl_ensure_code(aImage, CPL_ERROR_NULL_INPUT);
01235 cpl_ensure_code(aX || aY, CPL_ERROR_NULL_INPUT);
01236
01237 cpl_image *im = cpl_image_extract(aImage, aX1, aY1, aX2, aY2);
01238 cpl_ensure_code(im, cpl_error_get_code());
01239
01240 double bg = 0.;
01241 if (aBgType == MUSE_UTILS_CENTROID_MEAN) {
01242 bg = cpl_image_get_mean(im);
01243 } else if (aBgType == MUSE_UTILS_CENTROID_MEDIAN) {
01244 bg = cpl_image_get_median(im);
01245 } else {
01246 cpl_ensure_code(aBgType == MUSE_UTILS_CENTROID_NORMAL,
01247 CPL_ERROR_ILLEGAL_INPUT);
01248 }
01249 cpl_image_subtract_scalar(im, bg);
01250
01251
01252 if (aX) {
01253 cpl_image *row = cpl_image_collapse_create(im, 0);
01254 double w = 0.,
01255 f = 0.;
01256 int i, n = cpl_image_get_size_x(row);
01257 for (i = 1; i <= n; i++) {
01258 int err;
01259 double value = cpl_image_get(row, i, 1, &err);
01260 if (err || (value < 0 && aBgType != MUSE_UTILS_CENTROID_NORMAL)) {
01261 continue;
01262 }
01263 w += i * value;
01264 f += value;
01265 }
01266 *aX = w / f + aX1 - 1;
01267 cpl_image_delete(row);
01268 }
01269
01270 if (aY) {
01271 cpl_image *col = cpl_image_collapse_create(im, 1);
01272 double w = 0.,
01273 f = 0.;
01274 int j, n = cpl_image_get_size_y(col);
01275 for (j = 1; j <= n; j++) {
01276 int err;
01277 double value = cpl_image_get(col, 1, j, &err);
01278 if (err || (value < 0 && aBgType != MUSE_UTILS_CENTROID_NORMAL)) {
01279 continue;
01280 }
01281 w += j * value;
01282 f += value;
01283 }
01284 *aY = w / f + aY1 - 1;
01285 cpl_image_delete(col);
01286 }
01287 cpl_image_delete(im);
01288
01289 return CPL_ERROR_NONE;
01290 }
01291
01292
01322
01323 cpl_error_code
01324 muse_utils_get_centroid(const cpl_matrix *aPositions,
01325 const cpl_vector *aValues, const cpl_vector *aErrors,
01326 double *aX, double *aY, muse_utils_centroid_type aBgType)
01327 {
01328 cpl_ensure_code(aPositions && aValues, CPL_ERROR_NULL_INPUT);
01329 cpl_ensure_code(cpl_matrix_get_ncol(aPositions) == 2, CPL_ERROR_ILLEGAL_INPUT);
01330 int npoints = cpl_matrix_get_nrow(aPositions);
01331 cpl_ensure_code(npoints == cpl_vector_get_size(aValues), CPL_ERROR_ILLEGAL_INPUT);
01332 if (aErrors) {
01333 cpl_ensure_code(cpl_vector_get_size(aValues) == cpl_vector_get_size(aErrors),
01334 CPL_ERROR_ILLEGAL_INPUT);
01335 }
01336 cpl_ensure_code(aX || aY, CPL_ERROR_NULL_INPUT);
01337
01338 const double *values = cpl_vector_get_data_const(aValues);
01339 double xcen = 0., ycen = 0.,
01340 weight = 0., bg = 0.;
01341 if (aBgType == MUSE_UTILS_CENTROID_MEAN) {
01342 bg = cpl_vector_get_mean(aValues);
01343 } else if (aBgType == MUSE_UTILS_CENTROID_MEDIAN) {
01344 bg = cpl_vector_get_median_const(aValues);
01345 } else {
01346 cpl_ensure_code(aBgType == MUSE_UTILS_CENTROID_NORMAL,
01347 CPL_ERROR_ILLEGAL_INPUT);
01348 }
01349
01350 int i;
01351 for (i = 0; i < npoints; i++) {
01352 double w = values[i] - bg;
01353 if (w < 0 && aBgType != MUSE_UTILS_CENTROID_NORMAL) {
01354 continue;
01355 }
01356 if (aErrors) {
01357 w /= cpl_vector_get(aErrors, i);
01358 }
01359 xcen += cpl_matrix_get(aPositions, i, 0) * w;
01360 ycen += cpl_matrix_get(aPositions, i, 1) * w;
01361 weight += w;
01362 }
01363 xcen /= weight;
01364 ycen /= weight;
01365
01366 if (aX) {
01367 *aX = xcen;
01368 }
01369 if (aY) {
01370 *aY = ycen;
01371 }
01372 return CPL_ERROR_NONE;
01373 }
01374
01375
01398
01399 static int
01400 muse_utils_multigauss(const double x[], const double p[], double *f)
01401 {
01402 const double xp = x[0];
01403 const cpl_size ncoeffs = p[0],
01404 npeaks = p[1];
01405 const double sigma = p[2 + ncoeffs];
01406 if (sigma == 0.0) {
01407 cpl_size i;
01408 for (i = 0; i < npeaks; i++) {
01409 if (p[2 + ncoeffs + 1 + i] == xp) {
01410 *f = DBL_MAX;
01411 return 0;
01412 }
01413 }
01414 *f = 0.;
01415 return 0;
01416 }
01417
01418
01419 *f = 0.;
01420
01421 cpl_size ic;
01422 for (ic = 0; ic < ncoeffs; ic++) {
01423 *f += p[2 + ic] * pow(xp, ic);
01424 }
01425
01426 cpl_size ip;
01427 for (ip = 0; ip < npeaks; ip++) {
01428 const double xi = p[3 + ncoeffs + ip],
01429 Ai = p[3 + ncoeffs + npeaks + ip],
01430 exponent = (xi - xp) / sigma;
01431 *f += Ai / CPL_MATH_SQRT2PI / sigma * exp(-0.5 * exponent*exponent);
01432 }
01433 #if 0
01434 printf("eval at %f --> %f\n", xp, *f);
01435 int i;
01436 for (i = 0; i < ncoeffs + 2*npeaks + 3; i++) {
01437 printf(" [%02d] %f\n", i, p[i]);
01438 }
01439 fflush(stdout);
01440 #endif
01441 return 0;
01442 }
01443
01444
01454
01455 static int
01456 muse_utils_dmultigauss(const double x[], const double p[], double f[])
01457 {
01458 const cpl_size ncoeffs = p[0],
01459 npeaks = p[1];
01460 const double sigma = p[2 + ncoeffs];
01461 if (sigma == 0.0) {
01462 memset(f, 0, sizeof(double) * (ncoeffs + 2*npeaks + 3));
01463 return 0;
01464 }
01465
01466 const double xp = x[0];
01467 f[0] = f[1] = 0.;
01468
01469 cpl_size ic;
01470 for (ic = 0; ic < ncoeffs; ic++) {
01471 f[2 + ic] = pow(xp, ic);
01472 }
01473
01474 f[2 + ncoeffs] = 0.;
01475 cpl_size ip;
01476 for (ip = 0; ip < npeaks; ip++) {
01477 const double xi = p[3 + ncoeffs + ip],
01478 Ai = p[3 + ncoeffs + npeaks + ip],
01479 exponent = (xi - xp) / sigma,
01480 expsq = exponent * exponent,
01481 expfunc = exp(-0.5 * expsq);
01482 f[2 + ncoeffs] -= Ai / CPL_MATH_SQRT2PI / (sigma*sigma)
01483 * (1 - expsq) * expfunc;
01484
01485 f[3 + ncoeffs + ip] = -Ai / CPL_MATH_SQRT2PI / (sigma*sigma*sigma)
01486 * (xi - xp) * expfunc;
01487
01488 f[3 + ncoeffs + npeaks + ip] = 1 / CPL_MATH_SQRT2PI / sigma * expfunc;
01489 }
01490 #if 0
01491 printf("deval at %f -->\n", xp);
01492 int i;
01493 for (i = 0; i < ncoeffs + 2*npeaks + 3; i++) {
01494 printf(" [%02d] %e %f\n", i, f[i], p[i]);
01495 }
01496 fflush(stdout);
01497 #endif
01498 return 0;
01499 }
01500
01501
01552
01553 cpl_error_code
01554 muse_utils_fit_multigauss_1d(const cpl_vector *aX, const cpl_bivector *aY,
01555 cpl_vector *aCenter, double *aSigma,
01556 cpl_vector *aFlux, cpl_vector *aPoly,
01557 double *aMSE, double *aRedChisq,
01558 cpl_matrix **aCovariance)
01559 {
01560 if (aCovariance) {
01561 *aCovariance = NULL;
01562 }
01563 cpl_ensure_code(aX && aY && aCenter && aSigma, CPL_ERROR_NULL_INPUT);
01564 cpl_size npoints = cpl_vector_get_size(aX);
01565 cpl_ensure_code(npoints == cpl_bivector_get_size(aY), CPL_ERROR_INCOMPATIBLE_INPUT);
01566 cpl_size npeaks = cpl_vector_get_size(aCenter);
01567 cpl_ensure_code(!aFlux || npeaks == cpl_vector_get_size(aFlux),
01568 CPL_ERROR_INCOMPATIBLE_INPUT);
01569 cpl_size ncoeffs = aPoly ? cpl_vector_get_size(aPoly) : 0,
01570 npars = ncoeffs + 1
01571 + 2 * npeaks ;
01572 cpl_ensure_code(!aRedChisq || npoints >= npars, CPL_ERROR_ILLEGAL_INPUT);
01573
01574
01575 cpl_matrix *x = cpl_matrix_wrap(npoints, 1, (double *)cpl_vector_get_data_const(aX));
01576 const cpl_vector *y = cpl_bivector_get_x_const(aY),
01577 *ye = cpl_bivector_get_y_const(aY);
01578
01579 cpl_vector *p = cpl_vector_new(npars + 2);
01580 int *pflags = cpl_calloc(npars + 2, sizeof(int));
01581
01582 cpl_vector_set(p, 0, ncoeffs);
01583 cpl_vector_set(p, 1, npeaks);
01584 cpl_size i;
01585 for (i = 2; i < npars + 2; i++) {
01586 pflags[i] = 1;
01587 }
01588 #if 0
01589 cpl_array *aflags = cpl_array_wrap_int(pflags, npars + 2);
01590 printf("aflags, non-zero means parameter is fitted by cpl_fit_lvmq():\n");
01591 cpl_array_dump(aflags, 0, 1000, stdout);
01592 fflush(stdout);
01593 cpl_array_unwrap(aflags);
01594 #endif
01595
01596 cpl_size j;
01597 for (j = 0, i = 2; j < ncoeffs; j++, i++) {
01598 cpl_vector_set(p, i, cpl_vector_get(aPoly, j));
01599 }
01600
01601 double sigma = fabs(*aSigma);
01602 if (*aSigma < 0) {
01603 pflags[i] = 0;
01604 }
01605 cpl_vector_set(p, i++, sigma);
01606
01607 for (j = 0; j < npeaks; j++, i++) {
01608 cpl_vector_set(p, i, cpl_vector_get(aCenter, j));
01609 }
01610
01611 for (j = 0; j < npeaks; j++, i++) {
01612 if (aFlux) {
01613 cpl_vector_set(p, i, cpl_vector_get(aFlux, j));
01614 } else {
01615 cpl_vector_set(p, i, 1.);
01616 }
01617 }
01618 #if 0
01619 printf("input parameters p and their pflags:\n");
01620 for (j = 0; j < cpl_vector_get_size(p); j++) {
01621 printf(" [%02d] %f %s\n", j, cpl_vector_get(p, j),
01622 pflags[j] ? "\tfitted" : "constant");
01623 }
01624 #endif
01625 cpl_matrix *covariance = NULL;
01626 cpl_error_code rc = cpl_fit_lvmq(x, NULL, y, ye, p, pflags,
01627 muse_utils_multigauss, muse_utils_dmultigauss,
01628 CPL_FIT_LVMQ_TOLERANCE, CPL_FIT_LVMQ_COUNT,
01629 CPL_FIT_LVMQ_MAXITER, aMSE, aRedChisq,
01630 &covariance);
01631 cpl_matrix_unwrap(x);
01632 cpl_free(pflags);
01633 #if 0
01634 printf("output parameters vector p (%e, %e):\n",
01635 aMSE ? sqrt(*aMSE) : 0.0, aRedChisq ? *aRedChisq : 0.0);
01636 cpl_vector_dump(p, stdout);
01637 fflush(stdout);
01638 #endif
01639
01640 for (j = 0, i = 2; j < ncoeffs; j++, i++) {
01641 cpl_vector_set(aPoly, j, cpl_vector_get(p, i));
01642 }
01643
01644
01645
01646 *aSigma = fabs(cpl_vector_get(p, i++));
01647 for (j = 0; j < npeaks; j++, i++) {
01648 cpl_vector_set(aCenter, j, cpl_vector_get(p, i));
01649 }
01650
01651 if (aFlux) {
01652 for (j = 0; j < npeaks; j++, i++) {
01653 cpl_vector_set(aFlux, j, cpl_vector_get(p, i));
01654 }
01655 }
01656
01657
01658 if (aCovariance) {
01659 *aCovariance = cpl_matrix_extract(covariance, 2, 2, 1, 1,
01660 cpl_matrix_get_nrow(covariance) - 2,
01661 cpl_matrix_get_ncol(covariance) - 2);
01662 }
01663 cpl_matrix_delete(covariance);
01664 cpl_vector_delete(p);
01665 return rc;
01666 }
01667
01668 #if MOFFAT_USE_MUSE_OPTIMIZE
01669
01670
01671 typedef struct {
01672 const cpl_matrix *positions;
01673 const cpl_vector *values;
01674 const cpl_vector *errors;
01675 } fitdata_t;
01676
01677
01689
01690 static cpl_error_code
01691 muse_moffat_2d_optfunc(void *aData, cpl_array *aParams, cpl_array *aResiduals)
01692 {
01693 const cpl_matrix *pos = ((fitdata_t *)aData)->positions;
01694 const cpl_vector *val = ((fitdata_t *)aData)->values,
01695 *err = ((fitdata_t *)aData)->errors;
01696
01697 const double *p = cpl_array_get_data_double_const(aParams);
01698 double *residuals = cpl_array_get_data_double(aResiduals);
01699 int i, npoints = cpl_vector_get_size(val);
01700 for (i = 0; i < npoints; i++) {
01701 double xterm = (cpl_matrix_get(pos, i, 0) - p[2]) / p[4],
01702 yterm = (cpl_matrix_get(pos, i, 1) - p[3]) / p[5],
01703 crossterm = 2 * p[7] * xterm * yterm,
01704 base = 1 + (xterm*xterm + crossterm + yterm*yterm) / (1 + p[7]*p[7]),
01705 moffat = p[0] + p[1] * (p[6] - 1)
01706 / (CPL_MATH_PI * p[4]*p[5] * sqrt(1 - p[7]*p[7]))
01707 * pow(base, -p[6]);
01708
01709 residuals[i] = cpl_vector_get(val, i) - moffat;
01710
01711 residuals[i] /= cpl_vector_get(err, i);
01712 }
01713 return CPL_ERROR_NONE;
01714 }
01715
01716 #else
01717
01718
01730
01731 static int
01732 muse_moffat_2d_function(const double xy[], const double p[], double *f)
01733 {
01734 double xterm = (xy[0] - p[2]) / p[4],
01735 yterm = (xy[1] - p[3]) / p[5],
01736 crossterm = 2 * p[7] * xterm * yterm,
01737 rhoterm = 1. - p[7]*p[7],
01738 base = 1. + (xterm*xterm + crossterm + yterm*yterm) / rhoterm;
01739 *f = p[0] + p[1] * (p[6] - 1.) / (CPL_MATH_PI * p[4]*p[5] * sqrt(rhoterm))
01740 * pow(base, -p[6]);
01741
01742
01743 return 0;
01744 }
01745
01746
01758
01759 static int
01760 muse_moffat_2d_derivative(const double xy[], const double p[], double f[])
01761 {
01762 double xterm = (xy[0] - p[2]) / p[4],
01763 yterm = (xy[1] - p[3]) / p[5],
01764 crossterm = 2 * p[7] * xterm * yterm,
01765 rhoterm = 1. - p[7]*p[7],
01766 base = 1. + (xterm*xterm + crossterm + yterm*yterm) / (rhoterm);
01767 f[0] = 1;
01768 f[1] = (p[6] - 1.) / (CPL_MATH_PI * p[4]*p[5] * sqrt(rhoterm))
01769 * pow(base, -p[6]);
01770 f[2] = 2 * p[1] * p[6]*(p[6] - 1.)
01771 / (CPL_MATH_PI * p[4]*p[4] * p[5] * pow(rhoterm, 3./2.))
01772 * (xterm + p[7] * yterm) * pow(base, -p[6]-1.);
01773 f[3] = 2 * p[1] * p[6]*(p[6] - 1.)
01774 / (CPL_MATH_PI * p[4] * p[5]*p[5] * pow(rhoterm, 3./2.))
01775 * (yterm + p[7] * xterm) * pow(base, -p[6]-1.);
01776 f[4] = p[1] * (p[6] - 1.)
01777 / (CPL_MATH_PI * p[4]*p[4] * p[5] * sqrt(rhoterm))
01778 * (-pow(base, -p[6]) + 2 * p[6] / (rhoterm) * pow(base, -p[6]-1.)
01779 * (xterm*xterm + 0.5*crossterm));
01780 f[5] = p[1] * (p[6] - 1.)
01781 / (CPL_MATH_PI * p[4] * p[5]*p[5] * sqrt(rhoterm))
01782 * (-pow(base, -p[6]) + 2 * p[6] / (rhoterm) * pow(base, -p[6]-1.)
01783 * (yterm*yterm + 0.5*crossterm));
01784 f[6] = p[1] / (CPL_MATH_PI * p[4]*p[5] * sqrt(rhoterm))
01785 * pow(base, -p[6]) * (1. + (p[6] - 1.) * log(base));
01786 f[7] = p[1] * (p[6] - 1.)
01787 / (CPL_MATH_PI * p[4]*p[5] * pow(rhoterm, 3./2.))
01788 * (p[7] * pow(base, -p[6])
01789 - 2. * p[6] * pow(base, -p[6]-1.)
01790 * (xterm*yterm * (1 + 2*p[7]*p[7] / rhoterm)
01791 + p[7] / rhoterm * (xterm*xterm + yterm*yterm) ));
01792
01793
01794 return 0;
01795 }
01796
01797 #endif
01798
01799
01872
01873 cpl_error_code
01874 muse_utils_fit_moffat_2d(const cpl_matrix *aPositions,
01875 const cpl_vector *aValues, const cpl_vector *aErrors,
01876 cpl_array *aParams, cpl_array *aPErrors,
01877 const cpl_array *aPFlags,
01878 double *aRMS, double *aRedChisq)
01879 {
01880
01881 if (!aPositions) {
01882 return cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
01883 "Missing input positions.");
01884 }
01885 if (!aValues) {
01886 return cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
01887 "Missing input values / errors.");
01888 }
01889 if (cpl_matrix_get_ncol(aPositions) != 2) {
01890 return cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
01891 "Input positions are not for two-dimensional data.");
01892 }
01893 if (cpl_vector_get_size(aValues) != cpl_matrix_get_nrow(aPositions)) {
01894 return cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
01895 "Input positions and values data must have same size.");
01896 }
01897 if (aErrors && (cpl_vector_get_size(aValues) != cpl_vector_get_size(aErrors))) {
01898 return cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
01899 "Input vectors must have same size.");
01900 }
01901 if (!aParams) {
01902 return cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
01903 "Missing input parameters array.");
01904 }
01905 if (cpl_array_get_type(aParams) != CPL_TYPE_DOUBLE) {
01906 return cpl_error_set_message(__func__, CPL_ERROR_INVALID_TYPE,
01907 "Parameters array should be CPL_TYPE_DOUBLE.");
01908 }
01909 if (aPErrors && (cpl_array_get_type(aPErrors) != CPL_TYPE_DOUBLE)) {
01910 return cpl_error_set_message(__func__, CPL_ERROR_INVALID_TYPE,
01911 "Parameters error array should be CPL_TYPE_DOUBLE.");
01912 }
01913 if (aPFlags && (cpl_array_get_type(aPFlags) != CPL_TYPE_INT)) {
01914 return cpl_error_set_message(__func__, CPL_ERROR_INVALID_TYPE,
01915 "Parameters error array should be CPL_TYPE_INT.");
01916 }
01917 if ((aPErrors || aRedChisq) && !aErrors) {
01918 return cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND,
01919 "Missing input parameters errors.");
01920 }
01921 int npoints = cpl_matrix_get_nrow(aPositions);
01922 if (npoints < 8) {
01923
01924 return cpl_error_set_message(__func__, CPL_ERROR_SINGULAR_MATRIX,
01925 "%d are not enough points to fit a Moffat profile.",
01926 npoints);
01927 }
01928
01929 int pflags[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
01930
01931 if (aPFlags) {
01932 int idx, nparam = 0;
01933 for (idx = 0; idx < 8; idx++) {
01934 int err, flag = cpl_array_get_int(aPFlags, idx, &err);
01935 if (err || flag) {
01936 continue;
01937 }
01938 pflags[idx] = 0;
01939 nparam++;
01940 cpl_array_get_double(aParams, idx, &err);
01941 if (err) {
01942 return cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
01943 "Missing frozen value for parameter %d.", idx);
01944 }
01945 }
01946
01947 if (nparam == 8) {
01948 return cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
01949 "No free parameters");
01950 }
01951 }
01952
01953
01954
01955
01956
01957
01958 int invalid;
01959 double bg = cpl_array_get_double(aParams, 0, &invalid);
01960 if (invalid) {
01961 bg = cpl_vector_get_median_const(aValues);
01962 }
01963
01964
01965
01966 double volguess = (cpl_vector_get_mean(aValues) - bg) * npoints;
01967 if (fabs(volguess) < FLT_EPSILON) {
01968
01969 cpl_array_set_double(aParams, 0, bg);
01970 cpl_array_set_double(aParams, 1, 0.);
01971 cpl_array_set_invalid(aParams, 2);
01972 cpl_array_set_invalid(aParams, 3);
01973 cpl_array_set_invalid(aParams, 4);
01974 cpl_array_set_invalid(aParams, 5);
01975 cpl_array_set_double(aParams, 6, 1.);
01976 #if 0
01977 printf("flat Moffat:\n");
01978 cpl_array_dump(aParams, 0, 10, stdout);
01979 fflush(stdout);
01980 #endif
01981 return CPL_ERROR_NONE;
01982 }
01983
01984
01985
01986
01987 double xcen, ycen;
01988 muse_utils_get_centroid(aPositions, aValues, aErrors, &xcen, &ycen,
01989 MUSE_UTILS_CENTROID_MEDIAN);
01990 double xc = cpl_array_get_double(aParams, 2, &invalid);
01991 if (invalid) {
01992 xc = xcen;
01993 }
01994 double yc = cpl_array_get_double(aParams, 3, &invalid);
01995 if (invalid) {
01996 yc = ycen;
01997 }
01998
01999
02000
02001
02002
02003 double beta = cpl_array_get_double(aParams, 6, &invalid);
02004 if (invalid) {
02005 beta = 2.5;
02006 }
02007
02008
02009
02010
02011
02012
02013 double alphay, alphax = cpl_array_get_double(aParams, 4, &invalid);
02014 if (invalid) {
02015 alphay = cpl_array_get_double(aParams, 5, &invalid);
02016 if (invalid) {
02017 double amplitude = 0.;
02018 if (volguess > 0.) {
02019 amplitude = cpl_vector_get_max(aValues) - bg;
02020 } else {
02021 amplitude = cpl_vector_get_min(aValues) - bg;
02022 }
02023 double halfpeak = amplitude / 2. + bg,
02024 limit = amplitude * 0.01;
02025 const double *values = cpl_vector_get_data_const(aValues);
02026 cpl_vector *vradius = cpl_vector_new(1);
02027 int i, nfound;
02028 do {
02029 nfound = 0;
02030 for (i = 0; i < npoints; i++) {
02031 if (values[i] > halfpeak - limit && values[i] < halfpeak + limit) {
02032 cpl_vector_set_size(vradius, nfound + 1);
02033 double radius = sqrt(pow(cpl_matrix_get(aPositions, i, 0) - xcen, 2)
02034 + pow(cpl_matrix_get(aPositions, i, 1) - ycen, 2));
02035 #if 0
02036 printf("radius(%d, %d) = %f\n", i, nfound+1, radius);
02037 #endif
02038 cpl_vector_set(vradius, nfound++, radius);
02039 }
02040 }
02041
02042
02043 limit *= 2;
02044 #if 0
02045 printf("found %d points (limit = %f)\n", nfound, limit / 2);
02046 #endif
02047 } while (nfound < 3 && isfinite(limit));
02048 if (!isfinite(limit)) {
02049
02050
02051 alphax = alphay = 1.;
02052 } else {
02053
02054
02055
02056 alphax = alphay = cpl_vector_get_mean(vradius) / sqrt(pow(2., 1./beta)-1);
02057 #if 0
02058 printf("estimated alphas = %f from radius %f\n", alphax, cpl_vector_get_mean(vradius));
02059 fflush(stdout);
02060 #endif
02061 }
02062 cpl_vector_delete(vradius);
02063 } else {
02064 alphax = alphay;
02065 }
02066 } else {
02067 alphay = cpl_array_get_double(aParams, 5, &invalid);
02068 if (invalid) {
02069 alphay = alphax;
02070 }
02071 }
02072
02073
02074
02075 double volume = cpl_array_get_double(aParams, 1, &invalid);
02076 if (invalid) {
02077
02078
02079
02080 volume = volguess;
02081 }
02082
02083
02084
02085
02086 double rho = cpl_array_get_double(aParams, 7, &invalid);
02087 if (invalid) {
02088 rho = 0.;
02089 }
02090
02091
02092 cpl_vector *params = cpl_vector_new(8);
02093 cpl_vector_set(params, 0, bg);
02094 cpl_vector_set(params, 1, volume);
02095 cpl_vector_set(params, 2, xc);
02096 cpl_vector_set(params, 3, yc);
02097 cpl_vector_set(params, 4, alphax);
02098 cpl_vector_set(params, 5, alphay);
02099 cpl_vector_set(params, 6, beta);
02100 cpl_vector_set(params, 7, rho);
02101 #if 0
02102 printf("initial guess values for Moffat (vol %e):\n", (cpl_vector_get_mean(aValues) - bg) * npoints);
02103 cpl_vector_dump(params, stdout);
02104 fflush(stdout);
02105 #endif
02106 cpl_matrix *covariance = NULL;
02107
02108 cpl_error_code rc = CPL_ERROR_NONE;
02109 #if MOFFAT_USE_MUSE_OPTIMIZE
02110 fitdata_t fitdata;
02111 fitdata.positions = aPositions;
02112 fitdata.values = aValues;
02113 fitdata.errors = aErrors;
02114 cpl_array *optparams = cpl_array_wrap_double(cpl_vector_get_data(params), 8);
02115 rc = muse_cpl_optimize_lvmq(&fitdata, optparams, npoints,
02116 muse_moffat_2d_optfunc, NULL);
02117 cpl_array_unwrap(optparams);
02118 #else
02119 cpl_errorstate prestate = cpl_errorstate_get();
02120 rc = cpl_fit_lvmq(aPositions, NULL, aValues, aErrors, params, pflags,
02121 muse_moffat_2d_function, muse_moffat_2d_derivative,
02122 CPL_FIT_LVMQ_TOLERANCE, CPL_FIT_LVMQ_COUNT,
02123 CPL_FIT_LVMQ_MAXITER, aRMS,
02124 aErrors ? aRedChisq : NULL, aErrors ? &covariance : NULL);
02125 #endif
02126 if (aRMS) {
02127 *aRMS = sqrt(*aRMS);
02128 }
02129
02130 #if 0
02131 printf("Moffat fit (rc=%d, %s):\n", rc, cpl_error_get_message());
02132 cpl_vector_dump(params, stdout);
02133 fflush(stdout);
02134 #endif
02135 if (rc == CPL_ERROR_NONE || rc == CPL_ERROR_SINGULAR_MATRIX ||
02136 rc == CPL_ERROR_CONTINUE) {
02137
02138
02139
02140
02141
02142 if (isfinite(cpl_vector_get(params, 0)) &&
02143 isfinite(cpl_vector_get(params, 1)) &&
02144 isfinite(cpl_vector_get(params, 2)) &&
02145 isfinite(cpl_vector_get(params, 3)) &&
02146 isfinite(cpl_vector_get(params, 4)) &&
02147 isfinite(cpl_vector_get(params, 5)) &&
02148 isfinite(cpl_vector_get(params, 6)) &&
02149 isfinite(cpl_vector_get(params, 7))) {
02150
02151 rc = CPL_ERROR_NONE;
02152 cpl_errorstate_set(prestate);
02153
02154
02155
02156
02157 cpl_array_set_double(aParams, 0, cpl_vector_get(params, 0));
02158 cpl_array_set_double(aParams, 1, cpl_vector_get(params, 1));
02159 cpl_array_set_double(aParams, 2, cpl_vector_get(params, 2));
02160 cpl_array_set_double(aParams, 3, cpl_vector_get(params, 3));
02161 cpl_array_set_double(aParams, 4, fabs(cpl_vector_get(params, 4)));
02162 cpl_array_set_double(aParams, 5, fabs(cpl_vector_get(params, 5)));
02163 cpl_array_set_double(aParams, 6, cpl_vector_get(params, 6));
02164 cpl_array_set_double(aParams, 7, cpl_vector_get(params, 7));
02165
02166 if (aErrors && covariance) {
02167 int idx;
02168 for (idx = 0; idx < 8; idx++) {
02169 if (pflags[idx] && aPErrors) {
02170 cpl_array_set_double(aPErrors, idx,
02171 sqrt(cpl_matrix_get(covariance, idx, idx)));
02172 }
02173 }
02174 }
02175
02176
02177 }
02178 }
02179 cpl_matrix_delete(covariance);
02180 cpl_vector_delete(params);
02181
02182 return rc;
02183 }
02184
02185
02228
02229 cpl_polynomial *
02230 muse_utils_iterate_fit_polynomial(cpl_matrix *aPos, cpl_vector *aVal,
02231 cpl_vector *aErr, cpl_table *aExtra,
02232 const unsigned int aOrder, const double aRSigma,
02233 double *aMSE, double *aChiSq)
02234 {
02235
02236 if (aMSE) {
02237 *aMSE = DBL_MAX;
02238 }
02239 if (aChiSq) {
02240 *aChiSq = DBL_MAX;
02241 }
02242 cpl_ensure(aPos && aVal, CPL_ERROR_NULL_INPUT, NULL);
02243 cpl_ensure(cpl_matrix_get_ncol(aPos) == cpl_vector_get_size(aVal),
02244 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
02245 if (aErr) {
02246 cpl_ensure(cpl_vector_get_size(aVal) == cpl_vector_get_size(aErr),
02247 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
02248 }
02249 if (aExtra) {
02250 cpl_ensure(cpl_vector_get_size(aVal) == cpl_table_get_nrow(aExtra),
02251 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
02252 }
02253
02254
02255 int idx;
02256 for (idx = 0; idx < cpl_vector_get_size(aVal); idx++) {
02257
02258 if (isfinite(cpl_vector_get(aVal, idx))) {
02259 continue;
02260 }
02261
02262 if (cpl_vector_get_size(aVal) == 1) {
02263 cpl_msg_warning(__func__, "Input vector only contained non-finite elements!");
02264 break;
02265 }
02266
02267 cpl_matrix_erase_columns(aPos, idx, 1);
02268 muse_cplvector_erase_element(aVal, idx);
02269 if (aErr) {
02270 muse_cplvector_erase_element(aErr, idx);
02271 }
02272
02273 if (aExtra) {
02274 cpl_table_erase_window(aExtra, idx, 1);
02275 }
02276 idx--;
02277 }
02278
02279
02280 int ndim = cpl_matrix_get_nrow(aPos);
02281 cpl_polynomial *fit = cpl_polynomial_new(ndim);
02282 int large_residuals = 1;
02283 while (large_residuals > 0) {
02284 const cpl_boolean sym = CPL_FALSE;
02285 cpl_size *mindeg = cpl_calloc(ndim, sizeof(cpl_size)),
02286 *maxdeg = cpl_malloc(ndim * sizeof(cpl_size));
02287 int i;
02288 for (i = 0; i < ndim; i++) {
02289 maxdeg[i] = aOrder;
02290 }
02291 cpl_error_code rc = cpl_polynomial_fit(fit, aPos, &sym, aVal, NULL,
02292 CPL_FALSE, mindeg, maxdeg);
02293 cpl_free(mindeg);
02294 cpl_free(maxdeg);
02295 const cpl_size coeff = 0;
02296 if (rc != CPL_ERROR_NONE || !isfinite(cpl_polynomial_get_coeff(fit, &coeff))) {
02297
02298 cpl_errorstate prestate = cpl_errorstate_get();
02299 #if 0
02300 printf("%s: output polynomial:\n", __func__);
02301 cpl_polynomial_dump(fit, stdout);
02302 printf("%s: positions and values that we tried to fit:\n", __func__);
02303 cpl_matrix_dump(aPos, stdout);
02304 cpl_vector_dump(aVal, stdout);
02305 fflush(stdout);
02306 #endif
02307 cpl_polynomial_delete(fit);
02308
02309 if (!cpl_errorstate_is_equal(prestate)) {
02310 cpl_errorstate_set(prestate);
02311 }
02312 return NULL;
02313 }
02314
02315
02316 cpl_vector *res = cpl_vector_new(cpl_vector_get_size(aVal));
02317 cpl_vector_fill_polynomial_fit_residual(res, aVal, NULL, fit, aPos, aChiSq);
02318 double rms = sqrt(cpl_vector_product(res, res) / cpl_vector_get_size(res));
02319 if (rms == 0.) {
02320 rms = DBL_MIN;
02321 }
02322
02323 #if 0
02324 printf("%s: polynomial fit (RMS %g chisq %g aRSigma %f -> limit %g):\n",
02325 __func__, rms, aChiSq ? *aChiSq : 0., aRSigma, aRSigma * rms);
02326 cpl_polynomial_dump(fit, stdout);
02327 fflush(stdout);
02328 char *title = cpl_sprintf("set title \"%s: RMS %g\"\n"
02329 "unset key\n", __func__, rms);
02330 cpl_plot_vector(title, "", "", res);
02331 cpl_free(title);
02332 #endif
02333
02334 large_residuals = 0;
02335 for (i = 0; i < cpl_vector_get_size(res); i++) {
02336
02337 if (fabs(cpl_vector_get(res, i)) < (aRSigma * rms)) {
02338
02339 continue;
02340 }
02341
02342
02343 #if 0
02344 cpl_msg_debug(__func__, "residual %f RMS %f aRSigma %f -> limit %f",
02345 cpl_vector_get(res, i), rms, aRSigma, aRSigma * rms);
02346 #endif
02347
02348 if (cpl_vector_get_size(res) == 1) {
02349 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT, "tried to "
02350 "remove the last vector/matrix element when "
02351 "checking fit residuals (residual %g RMS %g "
02352 "aRSigma %f -> limit %g)", cpl_vector_get(res, i),
02353 rms, aRSigma, aRSigma * rms);
02354 cpl_polynomial_delete(fit);
02355 fit = NULL;
02356 rms = sqrt(DBL_MAX);
02357 if (aChiSq) {
02358 *aChiSq = DBL_MAX;
02359 }
02360 large_residuals = 0;
02361 break;
02362 }
02363
02364 muse_cplvector_erase_element(res, i);
02365 cpl_matrix_erase_columns(aPos, i, 1);
02366 muse_cplvector_erase_element(aVal, i);
02367 if (aErr) {
02368 muse_cplvector_erase_element(aErr, i);
02369 }
02370
02371 if (aExtra) {
02372 cpl_table_erase_window(aExtra, i, 1);
02373 }
02374 large_residuals++;
02375 i--;
02376 }
02377 cpl_vector_delete(res);
02378 if (aMSE) {
02379 *aMSE = rms * rms;
02380 }
02381 }
02382
02383 return fit;
02384 }
02385
02386
02436
02437 double
02438 muse_utils_pixtable_fit_line_gaussian(muse_pixtable *aPixtable, double aLambda,
02439 double aHalfWidth, double aBinSize,
02440 float aLo, float aHi, unsigned char aIter,
02441 cpl_array *aResults, cpl_array *aErrors)
02442 {
02443 cpl_ensure(aPixtable && aPixtable->table && aPixtable->header,
02444 CPL_ERROR_NULL_INPUT, 0.);
02445
02446
02447
02448
02449 cpl_boolean flip = aLambda < 0.;
02450 double lambda = fabs(aLambda);
02451
02452
02453 cpl_table_unselect_all(aPixtable->table);
02454 cpl_table_or_selected_float(aPixtable->table, MUSE_PIXTABLE_LAMBDA,
02455 CPL_NOT_LESS_THAN, lambda - aHalfWidth);
02456 cpl_table_and_selected_float(aPixtable->table, MUSE_PIXTABLE_LAMBDA,
02457 CPL_NOT_GREATER_THAN, lambda + aHalfWidth);
02458 cpl_size nsel = cpl_table_count_selected(aPixtable->table);
02459 cpl_ensure(nsel > 0, CPL_ERROR_DATA_NOT_FOUND, 0.);
02460
02461
02462
02463 cpl_errorstate state = cpl_errorstate_get();
02464 cpl_table *spec = muse_resampling_spectrum_iterate(aPixtable, aBinSize,
02465 aLo, aHi, aIter);
02466 cpl_table_unselect_all(aPixtable->table);
02467 if (!cpl_errorstate_is_equal(state)) {
02468
02469 cpl_table_delete(spec);
02470 cpl_error_set(__func__, cpl_error_get_code());
02471 return 0.;
02472 }
02473 if (flip) {
02474
02475
02476 cpl_table_multiply_scalar(spec, "data", -1.);
02477 }
02478
02479
02480 cpl_size nbins = cpl_table_get_nrow(spec);
02481
02482 cpl_table_power_column(spec, "stat", 0.5);
02483 cpl_table_name_column(spec, "stat", "error");
02484 cpl_table_set_column_unit(spec, "error",
02485 cpl_table_get_column_unit(spec, "data"));
02486 #if 0
02487 char *fn = cpl_sprintf("spec_ifu%02hhu_%p_%.3f.fits",
02488 muse_utils_get_ifu(aPixtable->header),
02489 (void *)aPixtable, aLambda);
02490 cpl_msg_debug(__func__, "----> saving spectrum as \"%s\"", fn);
02491 cpl_table_save(spec, NULL, NULL, fn, CPL_IO_CREATE);
02492 cpl_free(fn);
02493 #endif
02494
02495 cpl_vector *pos = cpl_vector_wrap(nbins, cpl_table_get_data_double(spec, "lambda")),
02496 *val = cpl_vector_wrap(nbins, cpl_table_get_data_double(spec, "data")),
02497 *err = cpl_vector_wrap(nbins, cpl_table_get_data_double(spec, "error"));
02498 state = cpl_errorstate_get();
02499 double xc, xerr = 2 * aHalfWidth,
02500 sigma, area, bglevel, mse;
02501 cpl_matrix *covariance = NULL;
02502 cpl_error_code rc = cpl_vector_fit_gaussian(pos, NULL, val, err, CPL_FIT_ALL,
02503 &xc, &sigma, &area, &bglevel,
02504 &mse, NULL, &covariance);
02505 cpl_vector_unwrap(pos);
02506 cpl_vector_unwrap(val);
02507 cpl_vector_unwrap(err);
02508 cpl_table_delete(spec);
02509 if (rc == CPL_ERROR_CONTINUE) {
02510
02511 xerr = sqrt(sigma * sigma / area);
02512 cpl_errorstate_set(state);
02513 } else if (rc == CPL_ERROR_SINGULAR_MATRIX || !covariance) {
02514 xerr = sqrt(sigma * sigma / area);
02515 cpl_errorstate_set(state);
02516 } else {
02517 xerr = sqrt(cpl_matrix_get(covariance, 0, 0));
02518 #if 0
02519 cpl_msg_debug(__func__, "covariance matrix:");
02520 cpl_matrix_dump(covariance, stdout);
02521 fflush(stdout);
02522 #endif
02523 }
02524 if (aResults && cpl_array_get_type(aResults) == CPL_TYPE_DOUBLE) {
02525 cpl_array_set_size(aResults, 4);
02526 cpl_array_set_double(aResults, 0, xc);
02527 cpl_array_set_double(aResults, 1, sigma);
02528 cpl_array_set_double(aResults, 2, area);
02529 cpl_array_set_double(aResults, 3, bglevel);
02530 }
02531 if (aErrors && cpl_array_get_type(aErrors) == CPL_TYPE_DOUBLE) {
02532 cpl_array_set_size(aErrors, 4);
02533 cpl_array_set_double(aErrors, 0, xerr);
02534 if (rc != CPL_ERROR_NONE || !covariance) {
02535 cpl_array_fill_window_invalid(aErrors, 1, 3);
02536 } else {
02537 cpl_array_set_double(aErrors, 1, sqrt(cpl_matrix_get(covariance, 1, 1)));
02538 cpl_array_set_double(aErrors, 2, sqrt(cpl_matrix_get(covariance, 2, 2)));
02539 cpl_array_set_double(aErrors, 3, sqrt(cpl_matrix_get(covariance, 3, 3)));
02540 }
02541 }
02542 cpl_matrix_delete(covariance);
02543 cpl_msg_debug(__func__, "Gaussian fit (%s): %f +/- %f Angstrom, %f, %f, %f "
02544 "(RMS %f)", rc != CPL_ERROR_NONE ? cpl_error_get_message() : "",
02545 xc, xerr, bglevel, area, sigma, sqrt(mse));
02546 return xc;
02547 }
02548
02549
02564
02565 cpl_error_code
02566 muse_utils_copy_modified_header(cpl_propertylist *aH1, cpl_propertylist *aH2,
02567 const char *aKeyword, const char *aString)
02568 {
02569 cpl_ensure_code(aH1 && aH2 && aKeyword && aString, CPL_ERROR_NULL_INPUT);
02570 const char *hin = cpl_propertylist_get_string(aH1, aKeyword);
02571 cpl_ensure_code(hin, CPL_ERROR_ILLEGAL_INPUT);
02572 char *hstring = cpl_sprintf("%s (%s)", hin, aString);
02573 cpl_error_code rc = cpl_propertylist_update_string(aH2, aKeyword, hstring);
02574 cpl_free(hstring);
02575
02576 return rc;
02577 }
02578
02579
02605
02606 cpl_error_code
02607 muse_utils_set_hduclass(cpl_propertylist *aHeader, const char *aClass2,
02608 const char *aExtData, const char *aExtDQ,
02609 const char *aExtStat)
02610 {
02611 cpl_ensure_code(aHeader && aClass2 && aExtData, CPL_ERROR_NULL_INPUT);
02612 cpl_ensure_code(!strcmp(aClass2, "DATA") || !strcmp(aClass2, "ERROR") ||
02613 !strcmp(aClass2, "QUALITY"), CPL_ERROR_ILLEGAL_INPUT);
02614
02615
02616 #define ESO_HDU_HEADERS_REGEXP "HDU(CLASS|CLAS1|CLAS2|CLAS3|DOC|VERS)$" \
02617 "|^SCIDATA$|^QUAL(DATA|MASK)$|^ERRDATA$"
02618 cpl_propertylist_erase_regexp(aHeader, ESO_HDU_HEADERS_REGEXP, 0);
02619
02620 if (cpl_propertylist_has(aHeader, "EXTNAME")) {
02621 cpl_propertylist_insert_after_string(aHeader, "EXTNAME", "HDUCLASS", "ESO");
02622 } else {
02623 cpl_propertylist_append_string(aHeader, "HDUCLASS", "ESO");
02624 }
02625 cpl_propertylist_set_comment(aHeader, "HDUCLASS", "class name (ESO format)");
02626 cpl_propertylist_insert_after_string(aHeader, "HDUCLASS", "HDUDOC", "DICD");
02627 cpl_propertylist_set_comment(aHeader, "HDUDOC", "document with class description");
02628 cpl_propertylist_insert_after_string(aHeader, "HDUDOC", "HDUVERS",
02629 "DICD version 6");
02630 cpl_propertylist_set_comment(aHeader, "HDUVERS",
02631 "version number (according to spec v2.5.1)");
02632 cpl_propertylist_insert_after_string(aHeader, "HDUVERS", "HDUCLAS1", "IMAGE");
02633 cpl_propertylist_set_comment(aHeader, "HDUCLAS1", "Image data format");
02634 cpl_propertylist_insert_after_string(aHeader, "HDUCLAS1", "HDUCLAS2", aClass2);
02635 if (!strcmp(aClass2, "DATA")) {
02636 cpl_propertylist_set_comment(aHeader, "HDUCLAS2",
02637 "this extension contains the data itself");
02638
02639 if (aExtDQ) {
02640 cpl_propertylist_insert_after_string(aHeader, "HDUCLAS2", "QUALDATA", aExtDQ);
02641 }
02642 if (aExtStat) {
02643 cpl_propertylist_insert_after_string(aHeader, "HDUCLAS2", "ERRDATA", aExtStat);
02644 }
02645 } else if (!strcmp(aClass2, "ERROR")) {
02646 cpl_propertylist_set_comment(aHeader, "HDUCLAS2", "this extension contains variance");
02647 cpl_propertylist_insert_after_string(aHeader, "HDUCLAS2", "HDUCLAS3", "MSE");
02648 cpl_propertylist_set_comment(aHeader, "HDUCLAS3",
02649 "the extension contains variances (sigma**2)");
02650 cpl_propertylist_insert_after_string(aHeader, "HDUCLAS3", "SCIDATA", aExtData);
02651 if (aExtDQ) {
02652 cpl_propertylist_insert_after_string(aHeader, "SCIDATA", "QUALDATA", aExtDQ);
02653 }
02654 } else {
02655 cpl_propertylist_set_comment(aHeader, "HDUCLAS2",
02656 "this extension contains bad pixel mask");
02657 cpl_propertylist_insert_after_string(aHeader, "HDUCLAS2", "HDUCLAS3", "FLAG32BIT");
02658 cpl_propertylist_set_comment(aHeader, "HDUCLAS3", "extension contains 32bit"
02659 " Euro3D bad pixel information");
02660
02661 cpl_propertylist_insert_after_long(aHeader, "HDUCLAS3", "QUALMASK", 0xFFFFFFFF);
02662 cpl_propertylist_set_comment(aHeader, "QUALMASK", "all non-zero values are bad");
02663 cpl_propertylist_insert_after_string(aHeader, "QUALMASK", "SCIDATA", aExtData);
02664 if (aExtStat) {
02665 cpl_propertylist_insert_after_string(aHeader, "SCIDATA", "ERRDATA", aExtStat);
02666 }
02667 }
02668
02669 if (cpl_propertylist_has(aHeader, "SCIDATA")) {
02670 cpl_propertylist_set_comment(aHeader, "SCIDATA", "pointer to the data extension");
02671 }
02672 if (cpl_propertylist_has(aHeader, "ERRDATA")) {
02673 cpl_propertylist_set_comment(aHeader, "ERRDATA", "pointer to the variance extension");
02674 }
02675 if (cpl_propertylist_has(aHeader, "QUALDATA")) {
02676 cpl_propertylist_set_comment(aHeader, "QUALDATA",
02677 "pointer to the bad pixel mask extension");
02678 }
02679
02680 return CPL_ERROR_NONE;
02681 }
02682
02683
02696
02697 void
02698 muse_utils_memory_dump(const char *aMarker)
02699 {
02700 char *exe = getenv("MUSE_DEBUG_MEMORY_PROGRAM");
02701 if (!exe) {
02702 return;
02703 }
02704
02705 printf("=== %s ===\n", aMarker);
02706 fflush(stdout);
02707 char command[1000];
02708 if (strlen(exe) > 0) {
02709 snprintf(command, 999,
02710 "ps -C %s -o comm,start_time,pid,tid,pcpu,stat,rss,size,vsize",
02711 exe);
02712 } else {
02713
02714 snprintf(command, 999,
02715 "ps -o comm,start_time,pid,tid,pcpu,stat,rss,size,vsize");
02716 }
02717 cpl_memory_dump();
02718 fflush(stderr);
02719 int rc = system(command);
02720 UNUSED_ARGUMENT(rc);
02721 }
02722
02723
02742
02743 cpl_image *
02744 muse_convolve_image(const cpl_image *aImage, const cpl_matrix *aKernel)
02745 {
02746 cpl_ensure(aImage && aKernel, CPL_ERROR_NULL_INPUT, NULL);
02747
02748 cpl_size nx = cpl_image_get_size_x(aImage);
02749 cpl_size ny = cpl_image_get_size_y(aImage);
02750 cpl_size nc = cpl_matrix_get_ncol(aKernel);
02751 cpl_size nr = cpl_matrix_get_nrow(aKernel);
02752
02753 cpl_ensure(cpl_image_get_type(aImage) == CPL_TYPE_DOUBLE,
02754 CPL_ERROR_INVALID_TYPE, NULL);
02755 cpl_ensure(nx % 2 == 0, CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
02756
02757 cpl_size kstart[2] = {(nx - nc) / 2, (ny - nr) / 2};
02758 cpl_size kend[2] = {kstart[0] + nc, kstart[1] + nr};
02759
02760 cpl_image *kernel = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
02761 double *_kernel = cpl_image_get_data_double(kernel);
02762
02763 const double *_aKernel = cpl_matrix_get_data_const(aKernel);
02764 cpl_size iy;
02765 for (iy = 0; iy < ny; ++iy) {
02766 cpl_size ix;
02767 for (ix = 0; ix < nx; ++ix) {
02768 cpl_size idx = nx * iy + ix;
02769 cpl_boolean inside = ((ix >= kstart[0]) && (ix < kend[0])) &&
02770 ((iy >= kstart[1]) && (iy < kend[1]));
02771 if (inside) {
02772 _kernel[idx] = _aKernel[nc * (iy - kstart[1]) + (ix - kstart[0])];
02773 }
02774 }
02775 }
02776
02777 cpl_size nxhalf = nx / 2 + 1;
02778 cpl_image *fft_image = cpl_image_new(nxhalf, ny, CPL_TYPE_DOUBLE_COMPLEX);
02779 cpl_image *fft_kernel = cpl_image_new(nxhalf, ny, CPL_TYPE_DOUBLE_COMPLEX);
02780
02781 cpl_error_code status;
02782 status = cpl_fft_image(fft_image, aImage, CPL_FFT_FORWARD);
02783 if (status != CPL_ERROR_NONE) {
02784 cpl_image_delete(fft_kernel);
02785 cpl_image_delete(fft_image);
02786 cpl_image_delete(kernel);
02787 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
02788 "FFT of input image failed!");
02789 return NULL;
02790 }
02791 status = cpl_fft_image(fft_kernel, kernel, CPL_FFT_FORWARD);
02792 if (status != CPL_ERROR_NONE) {
02793 cpl_image_delete(fft_kernel);
02794 cpl_image_delete(fft_image);
02795 cpl_image_delete(kernel);
02796 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
02797 "FFT of convolution kernel failed!");
02798 return NULL;
02799 }
02800 cpl_image_delete(kernel);
02801
02802 double complex *_fft_image = cpl_image_get_data_double_complex(fft_image);
02803 double complex *_fft_kernel = cpl_image_get_data_double_complex(fft_kernel);
02804
02805
02806
02807
02808
02809
02810
02811
02812
02813
02814
02815
02816
02817 for (iy = 0; iy < ny; ++iy) {
02818 cpl_size ix;
02819 for (ix = 0; ix < nxhalf; ++ix) {
02820 cpl_size idx = nxhalf * iy + ix;
02821 int sign = ((ix + iy) % 2) ? -1 : 1;
02822 _fft_image[idx] *= sign * _fft_kernel[idx] / (nx * ny);
02823 }
02824 }
02825 cpl_image_delete(fft_kernel);
02826
02827 cpl_image *result = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
02828 status = cpl_fft_image(result, fft_image, CPL_FFT_BACKWARD | CPL_FFT_NOSCALE);
02829 if (status != CPL_ERROR_NONE) {
02830 cpl_image_delete(result);
02831 cpl_image_delete(fft_image);
02832 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
02833 "Backward FFT of convolution result failed!");
02834 return NULL;
02835 }
02836 cpl_image_delete(fft_image);
02837
02838 return result;
02839 }
02840
02841
02842
02858
02859 muse_image *
02860 muse_fov_load(const char *aFilename)
02861 {
02862 muse_image *image = muse_image_new();
02863
02864 image->header = cpl_propertylist_load(aFilename, 0);
02865 if (!image->header) {
02866 cpl_error_set_message(__func__, cpl_error_get_code(), "Loading primary FITS "
02867 "header of \"%s\" did not succeed", aFilename);
02868 muse_image_delete(image);
02869 return NULL;
02870 }
02871
02872
02873 int extension = cpl_fits_find_extension(aFilename, EXTNAME_DATA);
02874 cpl_propertylist *hdata = cpl_propertylist_load(aFilename, extension);
02875 while (muse_pfits_get_naxis(hdata, 0) != 2) {
02876
02877
02878 cpl_msg_debug(__func__, "Skipping extension %d [%s]", extension,
02879 muse_pfits_get_extname(hdata));
02880 cpl_propertylist_delete(hdata);
02881 extension++;
02882 hdata = cpl_propertylist_load(aFilename, extension);
02883 }
02884 cpl_msg_debug(__func__, "Taking extension %d [%s]", extension,
02885 muse_pfits_get_extname(hdata));
02886
02887
02888 char *extname = cpl_strdup(muse_pfits_get_extname(hdata));
02889 image->data = cpl_image_load(aFilename, CPL_TYPE_FLOAT, 0, extension);
02890 if (!image->data) {
02891 cpl_error_set_message(__func__, MUSE_ERROR_READ_DATA, "Could not load "
02892 "extension %s from \"%s\"", extname, aFilename);
02893 muse_image_delete(image);
02894 cpl_free(extname);
02895 return NULL;
02896 }
02897
02898 if (cpl_propertylist_has(hdata, "BUNIT")) {
02899 cpl_propertylist_append_string(image->header, "BUNIT",
02900 muse_pfits_get_bunit(hdata));
02901 cpl_propertylist_set_comment(image->header, "BUNIT",
02902 cpl_propertylist_get_comment(hdata, "BUNIT"));
02903 } else {
02904 cpl_msg_warning(__func__, "No BUNIT given in extension %d [%s] of \"%s\"!",
02905 extension, extname, aFilename);
02906 }
02907
02908 if (!cpl_propertylist_has(hdata, "CUNIT1") ||
02909 !cpl_propertylist_has(hdata, "CUNIT2")) {
02910 cpl_msg_warning(__func__, "No WCS found in extension %d [%s] of \"%s\"!",
02911 extension, extname, aFilename);
02912 }
02913
02914
02915
02916 cpl_propertylist_erase_regexp(hdata, "(^ESO |" MUSE_WCS_KEYS ")", 1);
02917 cpl_propertylist_append(image->header, hdata);
02918 cpl_propertylist_delete(hdata);
02919
02920
02921
02922 if (extname && !strncmp(extname, EXTNAME_DATA, strlen(EXTNAME_DATA)+1)) {
02923
02924 extension = cpl_fits_find_extension(aFilename, EXTNAME_STAT);
02925 } else {
02926
02927 char *statname = cpl_sprintf("%s_STAT", extname);
02928 extension = cpl_fits_find_extension(aFilename, statname);
02929 cpl_free(statname);
02930 }
02931 if (extension > 0) {
02932 cpl_errorstate status = cpl_errorstate_get();
02933 image->stat = cpl_image_load(aFilename, CPL_TYPE_INT, 0, extension);
02934 if (!cpl_errorstate_is_equal(status)) {
02935 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
02936 cpl_errorstate_set(status);
02937 cpl_msg_debug(__func__, "Ignoring empty extension %s in \"%s\"",
02938 EXTNAME_STAT, aFilename);
02939 } else {
02940 cpl_error_set_message(__func__, MUSE_ERROR_READ_STAT, "Could not load "
02941 "extension %s from \"%s\"", EXTNAME_STAT, aFilename);
02942 muse_image_delete(image);
02943 cpl_free(extname);
02944 return NULL;
02945 }
02946 }
02947 }
02948
02949
02950
02951 if (extname && !strncmp(extname, EXTNAME_DATA, strlen(EXTNAME_DATA)+1)) {
02952
02953 extension = cpl_fits_find_extension(aFilename, EXTNAME_DQ);
02954 } else {
02955
02956 char *dqname = cpl_sprintf("%s_DQ", extname);
02957 extension = cpl_fits_find_extension(aFilename, dqname);
02958 cpl_free(dqname);
02959 }
02960 if (extension > 0) {
02961 cpl_errorstate status = cpl_errorstate_get();
02962 image->dq = cpl_image_load(aFilename, CPL_TYPE_INT, 0, extension);
02963 if (!cpl_errorstate_is_equal(status)) {
02964 cpl_errorstate_set(status);
02965 cpl_error_set_message(__func__, MUSE_ERROR_READ_DQ, "Could not load "
02966 "extension %s from \"%s\"", EXTNAME_DQ, aFilename);
02967 muse_image_delete(image);
02968 cpl_free(extname);
02969 return NULL;
02970 }
02971 muse_image_dq_to_nan(image);
02972 }
02973
02974 cpl_free(extname);
02975 return image;
02976 }