Changeset 30622
- Timestamp:
- Feb 13, 2011, 12:19:53 PM (15 years ago)
- Location:
- trunk/psModules/src/imcombine
- Files:
-
- 23 edited
- 1 copied
-
Makefile.am (modified) (1 diff)
-
pmReadoutCombine.c (modified) (1 diff)
-
pmStackReject.c (modified) (1 diff)
-
pmSubtraction.c (modified) (14 diffs)
-
pmSubtraction.h (modified) (4 diffs)
-
pmSubtractionAnalysis.c (modified) (1 diff)
-
pmSubtractionDeconvolve.c (modified) (1 diff)
-
pmSubtractionEquation.c (modified) (42 diffs)
-
pmSubtractionEquation.h (modified) (3 diffs)
-
pmSubtractionEquation.v0.c (modified) (1 diff)
-
pmSubtractionHermitian.c (modified) (1 diff)
-
pmSubtractionIO.c (modified) (1 diff)
-
pmSubtractionKernels.c (modified) (18 diffs)
-
pmSubtractionKernels.h (modified) (3 diffs)
-
pmSubtractionMask.c (modified) (1 diff)
-
pmSubtractionMatch.c (modified) (28 diffs)
-
pmSubtractionMatch.h (modified) (3 diffs)
-
pmSubtractionParams.c (modified) (2 diffs)
-
pmSubtractionStamps.c (modified) (12 diffs)
-
pmSubtractionStamps.h (modified) (3 diffs)
-
pmSubtractionThreads.c (modified) (2 diffs)
-
pmSubtractionTypes.h (copied) (copied from branches/eam_branches/ipp-20101205/psModules/src/imcombine/pmSubtractionTypes.h ) (2 diffs)
-
pmSubtractionVisual.c (modified) (13 diffs)
-
pmSubtractionVisual.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/imcombine/Makefile.am
r26893 r30622 30 30 pmStackReject.h \ 31 31 pmSubtraction.h \ 32 pmSubtractionTypes.h \ 32 33 pmSubtractionAnalysis.h \ 33 34 pmSubtractionEquation.h \ -
trunk/psModules/src/imcombine/pmReadoutCombine.c
r24907 r30622 33 33 params->blank = 0; 34 34 params->nKeep = 0; 35 params->frac High= 0.0;35 params->fracLow = 0.0; 36 36 params->fracHigh = 0.0; 37 37 params->iter = 1; -
trunk/psModules/src/imcombine/pmStackReject.c
r28405 r30622 7 7 #include <pslib.h> 8 8 9 #include "pmFPA.h" 10 #include "pmSubtractionTypes.h" 9 11 #include "pmSubtraction.h" 10 12 #include "pmSubtractionThreads.h" -
trunk/psModules/src/imcombine/pmSubtraction.c
r29777 r30622 20 20 #include "pmHDU.h" // Required for pmFPA.h 21 21 #include "pmFPA.h" 22 #include "pmSubtractionTypes.h" 22 23 #include "pmSubtractionStamps.h" 23 24 #include "pmSubtractionEquation.h" 24 25 #include "pmSubtractionVisual.h" 25 26 #include "pmSubtractionThreads.h" 27 28 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header); 26 29 27 30 #include "pmSubtraction.h" … … 773 776 774 777 if (convolutions) { 775 // Already done776 778 return convolutions; 777 779 } … … 787 789 } 788 790 791 792 bool pmSubtractionConvolveStampThread(psThreadJob *job) 793 { 794 PS_ASSERT_THREAD_JOB_NON_NULL(job, false); 795 796 pmSubtractionStamp *stamp = job->args->data[0]; // List of stamps 797 pmSubtractionKernels *kernels = job->args->data[1]; // Kernels 798 int footprint = PS_SCALAR_VALUE(job->args->data[2], S32); // Stamp index 799 800 return pmSubtractionConvolveStamp(stamp, kernels, footprint); 801 } 789 802 790 803 bool pmSubtractionConvolveStamp (pmSubtractionStamp *stamp, pmSubtractionKernels *kernels, int footprint) … … 818 831 } 819 832 833 #ifdef TESTING 834 for (int j = 0; j < kernels->num; j++) { 835 if (stamp->convolutions1) { 836 psString convName = NULL; 837 psStringAppend(&convName, "conv1_%03d_%03d.fits", index, j); 838 psFits *fits = psFitsOpen(convName, "w"); 839 psFree(convName); 840 psKernel *conv = stamp->convolutions1->data[j]; 841 psFitsWriteImage(fits, NULL, conv->image, 0, NULL); 842 psFitsClose(fits); 843 } 844 845 if (stamp->convolutions2) { 846 psString convName = NULL; 847 psStringAppend(&convName, "conv2_%03d_%03d.fits", index, j); 848 psFits *fits = psFitsOpen(convName, "w"); 849 psFree(convName); 850 psKernel *conv = stamp->convolutions2->data[j]; 851 psFitsWriteImage(fits, NULL, conv->image, 0, NULL); 852 psFitsClose(fits); 853 } 854 } 855 #endif 856 820 857 return true; 821 858 } 822 859 860 bool pmSubtractionConvolveStamps(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels) 861 { 862 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); 863 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); 864 865 psTimerStart("pmSubtractionConvolveStamps"); 866 867 int footprint = stamps->footprint; // Half-size of stamps 868 869 // We iterate over each stamp and generate the convolution if needed. We do NOT need the 870 // convolution if (a) it has already been calculated or (b) the stamp is not available for 871 // use (available = USED or CALCULATE) 872 873 for (int i = 0; i < stamps->num; i++) { 874 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 875 876 bool keep = false; 877 keep |= (stamp->status == PM_SUBTRACTION_STAMP_USED); 878 keep |= (stamp->status == PM_SUBTRACTION_STAMP_CALCULATE); 879 if (!keep) continue; 880 881 bool haveConvolutions = false; 882 if (kernels->mode == PM_SUBTRACTION_MODE_1) { 883 haveConvolutions = (stamp->convolutions1 != NULL); 884 } 885 if (kernels->mode == PM_SUBTRACTION_MODE_2) { 886 haveConvolutions = (stamp->convolutions2 != NULL); 887 } 888 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 889 haveConvolutions = (stamp->convolutions1 != NULL) && (stamp->convolutions2 != NULL); 890 } 891 if (haveConvolutions) { 892 continue; 893 } 894 895 if (pmSubtractionThreaded()) { 896 psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_CONVOLVE_STAMP"); 897 psArrayAdd(job->args, 1, stamp); 898 psArrayAdd(job->args, 1, kernels); 899 PS_ARRAY_ADD_SCALAR(job->args, footprint, PS_TYPE_S32); 900 if (!psThreadJobAddPending(job)) { 901 return false; 902 } 903 } else { 904 pmSubtractionConvolveStamp(stamp, kernels, footprint); 905 } 906 } 907 if (!psThreadPoolWait(true)) { 908 psError(psErrorCodeLast(), false, "Error waiting for threads."); 909 return false; 910 } 911 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolve stamps: %f sec", psTimerClear("pmSubtractionConvolveStamps")); 912 return true; 913 } 823 914 824 915 int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, pmSubtractionStampList *stamps, 825 const psVector *deviations, psImage *subMask, float sigmaRej)916 pmSubtractionQuality *match, psImage *subMask, float sigmaRej) 826 917 { 827 918 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); 828 919 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, -1); 829 PS_ASSERT_VECTOR_NON_NULL(deviations, -1);830 PS_ASSERT_VECTOR_TYPE(deviations, PS_TYPE_F32, -1);831 920 PS_ASSERT_IMAGE_NON_EMPTY(subMask, -1); 832 921 PS_ASSERT_IMAGE_TYPE(subMask, PS_TYPE_IMAGE_MASK, -1); 833 922 834 // I used to measure the rms deviation about zero, and use that as the sigma against which to clip, but 835 // the distribution is actually something like a chi^2 or Student's t, both of which become Gaussian-like 836 // with large N. Therefore, let's just treat this as a Gaussian distribution. 923 // Comment from PAP (r18287): I used to measure the rms deviation about zero, and use that as the 924 // sigma against which to clip, but the distribution is actually something like a chi^2 or 925 // Student's t, both of which become Gaussian-like with large N. Therefore, let's just 926 // treat this as a Gaussian distribution. 927 928 // Comment from EAM (r29777): The residual distribution is only chisq-like if the model is 929 // a good fit to the data. In the (likely) case that there is a systematic difference 930 // between the model and the data, the squared-residual distribution grows quadratically 931 // with increasing flux: the systematic residual flux is a constant factor times the source 932 // flux; the squared-residual is then of the form (k0 + k1*flux)^2, where k0 comes from the 933 // Gaussian distributed residual and k1*flux is the systematic residual error. 934 935 // By rejecting sources with the largest squared-residuals, the rejection biases against 936 // the brighter sources; in severe cases, this pushes the measurement to the weakest 937 // sources with the most noise. To account for this, let's fit a 2nd order polynomial to 938 // the distribution of flux vs squared-residual, subtract that fit, and reject sources 939 // which are significantly deviant from that distribution. 837 940 838 941 kernels->mean = NAN; … … 840 943 kernels->numStamps = -1; 841 944 842 int numStamps = 0; // Number of used stamps 843 psVector *mask = psVectorAlloc(stamps->num, PS_TYPE_VECTOR_MASK); // Mask, for statistics 844 psVectorInit(mask, 0); 845 for (int i = 0; i < stamps->num; i++) { 846 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 847 if (stamp->status != PM_SUBTRACTION_STAMP_USED) { 848 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff; 849 continue; 850 } 851 numStamps++; 852 } 853 psTrace("psModules.imcombine", 1, "Number of good stamps: %d\n", numStamps); 854 855 if (numStamps == 0) { 856 psError(PM_ERR_STAMPS, true, "No good stamps found."); 857 psFree(mask); 858 return -1; 859 } 860 861 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV | 862 PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_QUARTILE); // Statistics for deviatns 863 if (!psVectorStats(stats, deviations, NULL, mask, 0xff)) { 864 psError(PM_ERR_DATA, false, "Unable to measure statistics for deviations."); 945 psTrace("psModules.imcombine", 1, "Number of good stamps: %d\n", match->nGood); 946 947 // the chisq & flux vectors are calculated by pmSubtractionCalculateChisqAndMoments 948 949 // use 3hi/3lo sigma clipping on the chisq fit 950 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV); 951 stats->clipSigma = 5.0; 952 stats->clipIter = 2; 953 psPolynomial1D *model = psPolynomial1DAlloc (PS_POLYNOMIAL_ORD, 2); 954 955 bool result = psVectorClipFitPolynomial1D(model, stats, match->stampMask, 0xff, match->chisq, NULL, match->fluxes); 956 if (!result) { 957 psError(PM_ERR_DATA, false, "Unable to measure statistics for deviations."); 958 psFree(model); 865 959 psFree(stats); 866 psFree(mask); 867 return -1; 868 } 869 psFree(mask); 870 871 // XXX raise an error? 960 return -1; 961 } 872 962 if (isnan(stats->sampleMean)) { 963 psError(PM_ERR_DATA, false, "Unable to measure statistics for deviations."); 964 psFree(model); 873 965 psFree(stats); 874 966 return -1; 875 967 } 876 968 877 double mean, rms; // Mean and RMS of deviations 878 if (numStamps < MIN_SAMPLE_STATS) { 879 mean = stats->sampleMean; 880 rms = stats->sampleStdev; 881 } else { 882 mean = stats->sampleMedian; 883 rms = 0.74 * (stats->sampleUQ - stats->sampleLQ); 884 } 885 psFree(stats); 886 887 psTrace("psModules.imcombine", 1, "Mean: %f\n", mean); 888 psTrace("psModules.imcombine", 1, "RMS deviation: %f\n", rms); 889 890 kernels->mean = mean; 891 kernels->rms = rms; 892 kernels->numStamps = numStamps; 893 894 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Mean deviation from %d stamps: %lf +/- %lf", 895 numStamps, mean, rms); 896 897 if (!isfinite(sigmaRej) || sigmaRej <= 0.0) { 898 // User just wanted to calculate and record the deviation for posterity 899 return 0; 900 } 901 902 float limit = sigmaRej * rms; // Limit on maximum deviation 903 psTrace("psModules.imcombine", 1, "Deviation limit: %f\n", limit); 904 969 kernels->mean = stats->sampleMean; 970 kernels->rms = stats->sampleStdev; 971 kernels->numStamps = stats->clippedNvalues; 972 973 psLogMsg ("pmPSFtry", 4, "chisq vs flux model: %e + %e flux + %e flux^2\n", model->coeff[0], model->coeff[1], model->coeff[2]); 974 psLogMsg ("pmPSFtry", 4, "chisq vs flux resid: %f +/- %f\n", stats->sampleMean, stats->sampleStdev); 975 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Mean deviation from %d stamps: %lf +/- %lf", kernels->numStamps, kernels->mean, kernels->rms); 905 976 906 977 psString ds9name = NULL; // Filename for ds9 region file … … 914 985 int numRejected = 0; // Number of stamps rejected 915 986 int numGood = 0; // Number of good stamps 916 double newMean = 0.0; // New mean917 987 psString log = NULL; // Log message 918 psStringAppend(&log, "Rejecting stamps, mean = %f, threshold = %f\n", mean, limit); 988 989 // save DS9 region files for the stamps and mark for rejection and replacement 919 990 for (int i = 0; i < stamps->num; i++) { 920 991 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 921 if (stamp->status == PM_SUBTRACTION_STAMP_USED) { 992 if (stamp->status != PM_SUBTRACTION_STAMP_USED) { continue; } 993 if (match->stampMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) { 922 994 // Should we reject stars with low deviation? Well, if this is really a Gaussian-like 923 995 // distribution and they're low, then we have the right to ask why. Isn't it suspicious that … … 926 998 // subtract well, in which case very few (if any) stars will be legitimately rejected for being 927 999 // low. 928 if (fabsf(deviations->data.F32[i] - mean) > limit) { 929 // Mask out the stamp in the image so you it's not found again 930 psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d)\n", i, 931 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 932 psStringAppend(&log, "Stamp %d (%d,%d): %f\n", i, 933 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), 934 fabsf(deviations->data.F32[i] - mean)); 935 numRejected++; 936 for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) { 937 for (int x = stamp->x - footprint; x <= stamp->x + footprint; x++) { 938 subMask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= PM_SUBTRACTION_MASK_REJ; 939 } 940 } 941 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "red"); 942 943 // Set stamp for replacement 944 stamp->x = 0; 945 stamp->y = 0; 946 stamp->xNorm = NAN; 947 stamp->yNorm = NAN; 948 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 949 // Recalculate convolutions 950 psFree(stamp->convolutions1); 951 psFree(stamp->convolutions2); 952 stamp->convolutions1 = stamp->convolutions2 = NULL; 953 psFree(stamp->image1); 954 psFree(stamp->image2); 955 psFree(stamp->weight); 956 stamp->image1 = stamp->image2 = stamp->weight = NULL; 957 psFree(stamp->matrix); 958 stamp->matrix = NULL; 959 psFree(stamp->vector); 960 stamp->vector = NULL; 961 } else { 962 numGood++; 963 newMean += deviations->data.F32[i]; 964 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green"); 965 } 966 } 967 } 968 newMean /= numGood; 1000 psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d)\n", i, 1001 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 1002 psStringAppend(&log, "Stamp %d (%d,%d): %f : %f : %f\n", 1003 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), 1004 match->chisq->data.F32[i], match->fluxes->data.F32[i], match->chisq->data.F32[i] - psPolynomial1DEval(model, match->fluxes->data.F32[i])); 1005 numRejected++; 1006 for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) { 1007 for (int x = stamp->x - footprint; x <= stamp->x + footprint; x++) { 1008 subMask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= PM_SUBTRACTION_MASK_REJ; 1009 } 1010 } 1011 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "red"); 1012 1013 // Set stamp for replacement 1014 stamp->x = 0; 1015 stamp->y = 0; 1016 stamp->xNorm = NAN; 1017 stamp->yNorm = NAN; 1018 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 1019 // Recalculate convolutions 1020 psFree(stamp->convolutions1); 1021 psFree(stamp->convolutions2); 1022 stamp->convolutions1 = stamp->convolutions2 = NULL; 1023 psFree(stamp->image1); 1024 psFree(stamp->image2); 1025 psFree(stamp->weight); 1026 stamp->image1 = stamp->image2 = stamp->weight = NULL; 1027 psFree(stamp->matrix); 1028 stamp->matrix = NULL; 1029 psFree(stamp->vector); 1030 stamp->vector = NULL; 1031 } else { 1032 numGood++; 1033 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green"); 1034 } 1035 } 969 1036 970 1037 if (numRejected == 0) { … … 978 1045 } 979 1046 1047 psFree(model); 1048 psFree(stats); 1049 980 1050 if (numRejected > 0) { 981 psLogMsg("psModules.imcombine", PS_LOG_INFO, 982 "%d good stamps; %d rejected.\nMean deviation: %lf --> %lf\n", 983 numGood, numRejected, mean, newMean); 1051 psLogMsg("psModules.imcombine", PS_LOG_INFO, "%d good stamps; %d rejected.\n", numGood, numRejected); 984 1052 } else { 985 psLogMsg("psModules.imcombine", PS_LOG_INFO, 986 "%d good stamps; 0 rejected.\nMean deviation: %lf\n", 987 numGood, mean); 1053 psLogMsg("psModules.imcombine", PS_LOG_INFO, "%d good stamps; 0 rejected.\n", numGood); 988 1054 } 989 1055 … … 1373 1439 psFree(kernelErr2); 1374 1440 1441 static int nOut1 = 0; 1442 static int nOut2 = 0; 1443 1375 1444 // Calculate covariances 1376 1445 // This can be fairly involved, so we only do it for a small number of instances … … 1386 1455 psKernelTruncate(kernel, covarFrac); 1387 1456 covars->data[i] = psImageCovarianceCalculate(kernel, ro1->covariance); 1457 if (0) { 1458 char name[128]; 1459 snprintf (name, 128, "covar.sample1.%03d.fits", nOut1); 1460 psKernel *cov = covars->data[i]; 1461 psFitsWriteImageSimple (name, cov->image, NULL); 1462 1463 snprintf (name, 128, "incovar.sample1.%03d.fits", nOut1); 1464 psFitsWriteImageSimple (name, ro1->covariance->image, NULL); 1465 1466 snprintf (name, 128, "conv.sample1.%03d.fits", nOut1); 1467 psFitsWriteImageSimple (name, kernel->image, NULL); 1468 1469 fprintf (stderr, "incov: %d,%d; kern: %d,%d, outcov: %d,%d\n", 1470 ro1->covariance->image->numCols, ro1->covariance->image->numRows, 1471 kernel->image->numCols, kernel->image->numRows, 1472 cov->image->numCols, cov->image->numRows); 1473 1474 nOut1 ++; 1475 } 1388 1476 psFree(kernel); 1389 1477 } … … 1407 1495 psKernelTruncate(kernel, covarFrac); 1408 1496 covars->data[i] = psImageCovarianceCalculate(kernel, ro2->covariance); 1497 if (0) { 1498 char name[128]; 1499 snprintf (name, 128, "covar.sample2.%03d.fits", nOut2); 1500 psKernel *cov = covars->data[i]; 1501 psFitsWriteImageSimple (name, cov->image, NULL); 1502 1503 snprintf (name, 128, "incovar.sample2.%03d.fits", nOut2); 1504 psFitsWriteImageSimple (name, ro2->covariance->image, NULL); 1505 1506 snprintf (name, 128, "conv.sample2.%03d.fits", nOut2); 1507 psFitsWriteImageSimple (name, kernel->image, NULL); 1508 1509 fprintf (stderr, "incov: %d,%d; kern: %d,%d, outcov: %d,%d\n", 1510 ro2->covariance->image->numCols, ro2->covariance->image->numRows, 1511 kernel->image->numCols, kernel->image->numRows, 1512 cov->image->numCols, cov->image->numRows); 1513 1514 nOut2 ++; 1515 } 1409 1516 psFree(kernel); 1410 1517 } … … 1422 1529 psImageCovarianceSetThreads(oldThreads); 1423 1530 1424 // Copy anything that wasn't convolved 1531 // Copy anything that wasn't convolved (they may have been allocated though, so free them) 1425 1532 switch (kernels->mode) { 1426 1533 case PM_SUBTRACTION_MODE_1: 1427 1534 if (out2) { 1535 psFree(out2->image); 1536 psFree(out2->variance); 1537 psFree(out2->mask); 1538 psFree(out2->covariance); 1428 1539 out2->image = psMemIncrRefCounter(ro2->image); 1429 1540 out2->variance = psMemIncrRefCounter(ro2->variance); … … 1434 1545 case PM_SUBTRACTION_MODE_2: 1435 1546 if (out1) { 1547 psFree(out1->image); 1548 psFree(out1->variance); 1549 psFree(out1->mask); 1550 psFree(out1->covariance); 1436 1551 out1->image = psMemIncrRefCounter(ro1->image); 1437 1552 out1->variance = psMemIncrRefCounter(ro1->variance); … … 1479 1594 return true; 1480 1595 } 1596 1597 static void pmSubtractionQualityFree(pmSubtractionQuality *quality) { 1598 1599 psFree (quality->fluxes); 1600 psFree (quality->chisq); 1601 psFree (quality->moments); 1602 psFree (quality->stampMask); 1603 } 1604 1605 pmSubtractionQuality *pmSubtractionQualityAlloc() { 1606 1607 pmSubtractionQuality *quality = psAlloc(sizeof(pmSubtractionQuality)); // Stamp list to return 1608 psMemSetDeallocator(quality, (psFreeFunc)pmSubtractionQualityFree); 1609 1610 quality->fluxes = NULL; 1611 quality->chisq = NULL; 1612 quality->moments = NULL; 1613 quality->stampMask = NULL; 1614 1615 quality->score = NAN; 1616 quality->mode = PM_SUBTRACTION_MODE_ERR; 1617 quality->spatialOrder = -1; 1618 quality->nGood = 0; 1619 1620 return quality; 1621 } -
trunk/psModules/src/imcombine/pmSubtraction.h
r29601 r30622 14 14 #define PM_SUBTRACTION_H 15 15 16 #include <pslib.h> 17 18 #include <pmHDU.h> 19 #include <pmFPA.h> 20 #include <pmSubtractionKernels.h> 21 #include <pmSubtractionStamps.h> 16 // #include <pslib.h> 17 // #include <pmHDU.h> 18 // #include <pmFPA.h> 19 // #include <pmSubtractionKernels.h> 20 // #include <pmSubtractionStamps.h> 22 21 23 22 // if we use the original ppSub implementation, we subtract a central delta-function for all … … 30 29 /// @addtogroup imcombine Image Combinations 31 30 /// @{ 32 33 /// Mask values for the subtraction mask34 typedef enum {35 PM_SUBTRACTION_MASK_CLEAR = 0x00, // No masking36 PM_SUBTRACTION_MASK_BAD_1 = 0x01, // Image 1 is bad37 PM_SUBTRACTION_MASK_BAD_2 = 0x02, // Image 2 is bad38 PM_SUBTRACTION_MASK_CONVOLVE_1 = 0x04, // If image 1 is convolved, would be poor or bad39 PM_SUBTRACTION_MASK_CONVOLVE_2 = 0x08, // If image 2 is convolved, would be poor or bad40 PM_SUBTRACTION_MASK_CONVOLVE_BAD_1 = 0x10, // If image 1 is convolved, would be bad41 PM_SUBTRACTION_MASK_CONVOLVE_BAD_2 = 0x20, // If image 2 is convolved, would be bad42 PM_SUBTRACTION_MASK_BORDER = 0x40, // Image border43 PM_SUBTRACTION_MASK_REJ = 0x80, // Previously tried as a stamp, and rejected44 } pmSubtractionMasks;45 46 31 47 32 /// Number of terms in a polynomial … … 70 55 ); 71 56 57 bool pmSubtractionConvolveStamps(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels); 58 59 bool pmSubtractionConvolveStampThread(psThreadJob *job); 60 72 61 /// Reject stamps 73 62 int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, ///< Kernel parameters to update 74 63 pmSubtractionStampList *stamps, ///< Stamps 75 const psVector *deviations, ///< Deviations for each stamp64 pmSubtractionQuality *match, ///< data on the subtraction quality 76 65 psImage *subMask, ///< Subtraction mask 77 66 float sigmaRej ///< Number of RMS deviations above zero at which to reject … … 167 156 bool pmSubtractionSetFWHMs(float fwhm1, float fwhm2); 168 157 158 pmSubtractionQuality *pmSubtractionQualityAlloc(); 159 169 160 /// @} 170 161 #endif -
trunk/psModules/src/imcombine/pmSubtractionAnalysis.c
r29595 r30622 7 7 8 8 #include "pmFPA.h" 9 #include "pmSubtractionTypes.h" 9 10 #include "pmSubtraction.h" 10 11 #include "pmSubtractionKernels.h" -
trunk/psModules/src/imcombine/pmSubtractionDeconvolve.c
r26893 r30622 10 10 11 11 #include "pmFPA.h" 12 #include "pmSubtractionTypes.h" 12 13 #include "pmSubtractionKernels.h" 13 14 #include "pmSubtractionDeconvolve.h" -
trunk/psModules/src/imcombine/pmSubtractionEquation.c
r29598 r30622 8 8 9 9 #include "pmErrorCodes.h" 10 #include "pmVisual.h" 11 #include "pmFPA.h" 12 #include "pmSubtractionTypes.h" 10 13 #include "pmSubtraction.h" 11 14 #include "pmSubtractionKernels.h" … … 16 19 #include "pmSubtractionVisual.h" 17 20 18 //#define TESTING // TESTING output for debugging; may not work with threads! 19 20 //#define USE_WEIGHT // Include weight (1/variance) in equation? 21 22 // XXX TEST: 23 //# define USE_WINDOW // window to avoid neighbor contamination 21 //# define TESTING // TESTING output for debugging; may not work with threads! 22 # define USE_WEIGHT // Include weight (1/variance) in equation? 23 # define USE_WINDOW // window to avoid neighbor contamination 24 25 /* I believe we want to apply the WEIGHT to the chisq portions of the calculation (but not the WINDOW), 26 * and the WINDOW to the moments portiosn of the calculations (but not the WEIGHT) 27 * 28 */ 24 29 25 30 # define PENALTY false 26 31 # define MOMENTS (!PENALTY) 27 # define MOMENTS_PENALTY_SCALE 2 e-5 // XXX this value is not completely arbitrary, but I don't understand why it needs to be this value...32 # define MOMENTS_PENALTY_SCALE 20 // up-weight the moments somewhat 28 33 29 34 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 107 112 cc *= weight->kernel[y][x]; 108 113 } 109 if (window) { 114 // XXX NOTE: do NOT apply the window to the chisq portions of the calculation 115 if (false && window) { 110 116 cc *= window->kernel[y][x]; 111 117 } … … 138 144 rc *= wtVal; 139 145 } 140 if (window) { 146 // XXX NOTE: do NOT apply the window to the chisq portions of the calculation 147 if (false && window) { 141 148 float winVal = window->kernel[y][x]; 142 149 ic *= winVal; … … 173 180 } 174 181 182 # define RENORM_BY_FLUX 0 175 183 176 184 // Calculate the least-squares matrix and vector for dual convolution … … 268 276 for (int y = - footprint; y <= footprint; y++) { 269 277 for (int x = - footprint; x <= footprint; x++) { 278 279 // XXX NOTE: clipping low S/N pixels does not seem to work very well 280 if (false && weight) { 281 float i1 = image1->kernel[y][x]; 282 float i2 = image2->kernel[y][x]; 283 float sn = (i1 + i2) / sqrt (weight->kernel[y][x]); 284 if (sn < 0.5) continue; 285 } 286 270 287 double aa = iConv1->kernel[y][x] * jConv1->kernel[y][x] * PS_SQR(normValue); 271 288 double bb = iConv2->kernel[y][x] * jConv2->kernel[y][x]; 272 289 double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x] * normValue; 273 if (weight) { 274 float wtVal = weight->kernel[y][x]; 275 aa *= wtVal; 276 bb *= wtVal; 277 ab *= wtVal; 278 } 279 if (window) { 280 float wtVal = window->kernel[y][x]; 281 aa *= wtVal; 282 bb *= wtVal; 283 ab *= wtVal; 284 } 285 sumAA += aa; 286 sumBB += bb; 287 sumAB += ab; 290 291 float wtVal = (weight) ? weight->kernel[y][x] : 1.0; 292 sumAA += wtVal*aa; 293 sumBB += wtVal*bb; 294 sumAB += wtVal*ab; 288 295 289 296 if (MOMENTS) { 290 MxxAA += x*x*aa; 291 MyyAA += y*y*aa; 292 MxxBB += x*x*bb; 293 MyyBB += y*y*bb; 297 float winVal = (window) ? window->kernel[y][x] : 1.0; 298 MxxAA += winVal*x*x*aa; 299 MyyAA += winVal*y*y*aa; 300 MxxBB += winVal*x*x*bb; 301 MyyBB += winVal*y*y*bb; 294 302 } 295 303 } 296 304 } 297 305 306 // XXX does normSquare1,2 mess up the relative scaling? 307 // XXX no: normSquare1,2 is the sum of the flux^2 for the source 298 308 if (MOMENTS) { 299 309 MxxAA /= stamp->normSquare1 * PS_SQR(normValue); … … 305 315 // XXX this makes the Chisq portion independent of the normalization and star flux 306 316 // but may be mis-scaling between stars of different fluxes 317 # if (RENORM_BY_FLUX) 307 318 sumAA /= PS_SQR(stamp->normI2); 308 319 sumAB /= PS_SQR(stamp->normI2); 309 320 sumBB /= PS_SQR(stamp->normI2); 321 # endif 310 322 311 323 // fprintf (stderr, "i,j : %d %d : M(xx,yy)(AA,BB) : %f %f %f %f\n", i, j, MxxAA, MyyAA, MxxBB, MyyBB); … … 328 340 matrix->data.F64[iIndex][jIndex] += kernels->penalty * MxxAA * MOMENTS_PENALTY_SCALE; 329 341 matrix->data.F64[iIndex][jIndex] += kernels->penalty * MyyAA * MOMENTS_PENALTY_SCALE; 330 331 342 matrix->data.F64[jIndex][iIndex] += kernels->penalty * MxxAA * MOMENTS_PENALTY_SCALE; 332 343 matrix->data.F64[jIndex][iIndex] += kernels->penalty * MyyAA * MOMENTS_PENALTY_SCALE; … … 334 345 matrix->data.F64[iIndex + numParams][jIndex + numParams] += kernels->penalty * MxxBB * MOMENTS_PENALTY_SCALE; 335 346 matrix->data.F64[iIndex + numParams][jIndex + numParams] += kernels->penalty * MyyBB * MOMENTS_PENALTY_SCALE; 336 337 347 matrix->data.F64[jIndex + numParams][iIndex + numParams] += kernels->penalty * MxxBB * MOMENTS_PENALTY_SCALE; 338 348 matrix->data.F64[jIndex + numParams][iIndex + numParams] += kernels->penalty * MyyBB * MOMENTS_PENALTY_SCALE; … … 354 364 ab *= weight->kernel[y][x]; 355 365 } 356 if (window) { 366 // XXX NOTE: do NOT apply the window to the chisq portions of the calculation 367 if (false && window) { 357 368 ab *= window->kernel[y][x]; 358 369 } … … 363 374 // XXX this makes the Chisq portion independent of the normalization and star flux 364 375 // but may be mis-scaling between stars of different fluxes 376 # if (RENORM_BY_FLUX) 365 377 sumAB /= PS_SQR(stamp->normI2); 378 # endif 366 379 367 380 // Spatial variation of kernel coeffs … … 391 404 float i2 = image2->kernel[y][x]; 392 405 406 // XXX NOTE: clipping low S/N pixels does not seem to work very well 407 if (false && weight) { 408 float sn = (i1 + i2) / sqrt (weight->kernel[y][x]); 409 if (sn < 0.5) continue; 410 } 411 393 412 double ai2 = a * i2 * normValue; 394 413 double bi2 = b * i2; … … 396 415 double bi1 = b * i1 * normValue; 397 416 398 if (weight) { 399 float wtVal = weight->kernel[y][x]; 400 ai2 *= wtVal; 401 bi2 *= wtVal; 402 ai1 *= wtVal; 403 bi1 *= wtVal; 404 } 405 if (window) { 406 float wtVal = window->kernel[y][x]; 407 ai2 *= wtVal; 408 bi2 *= wtVal; 409 ai1 *= wtVal; 410 bi1 *= wtVal; 411 } 412 sumAI2 += ai2; 413 sumBI2 += bi2; 414 sumAI1 += ai1; 415 sumBI1 += bi1; 417 float wtVal = (weight) ? weight->kernel[y][x] : 1.0; 418 sumAI2 += wtVal*ai2; 419 sumBI2 += wtVal*bi2; 420 sumAI1 += wtVal*ai1; 421 sumBI1 += wtVal*bi1; 416 422 417 423 if (MOMENTS) { 418 MxxAI1 += x*x*ai1; 419 MyyAI1 += y*y*ai1; 420 MxxBI2 += x*x*bi2; 421 MyyBI2 += y*y*bi2; 424 float winVal = (window) ? window->kernel[y][x] : 1.0; 425 MxxAI1 += winVal*x*x*ai1; 426 MyyAI1 += winVal*y*y*ai1; 427 MxxBI2 += winVal*x*x*bi2; 428 MyyBI2 += winVal*y*y*bi2; 422 429 } 423 430 } … … 435 442 // XXX this makes the Chisq portion independent of the normalization and star flux 436 443 // but may be mis-scaling between stars of different fluxes 444 # if (RENORM_BY_FLUX) 437 445 sumAI1 /= PS_SQR(stamp->normI2); 438 446 sumBI1 /= PS_SQR(stamp->normI2); 439 447 sumAI2 /= PS_SQR(stamp->normI2); 440 448 sumBI2 /= PS_SQR(stamp->normI2); 449 # endif 441 450 442 451 // Spatial variation … … 788 797 stamp->normSquare2 = normSquare2; 789 798 790 psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "normValue: %f %f %f (%f %f)\n", normI1, normI2, stamp->norm, normSquare1, normSquare2);799 // psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "normValue: %f %f %f (%f %f)\n", normI1, normI2, stamp->norm, normSquare1, normSquare2); 791 800 792 801 return true; … … 800 809 pmSubtractionKernels *kernels = job->args->data[1]; // Kernels 801 810 int index = PS_SCALAR_VALUE(job->args->data[2], S32); // Stamp index 802 pmSubtractionEquationCalculationMode mode = PS_SCALAR_VALUE(job->args->data[3], S32); // calculation model 803 804 return pmSubtractionCalculateEquationStamp(stamps, kernels, index, mode); 805 } 806 807 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels, 808 int index, const pmSubtractionEquationCalculationMode mode) 811 812 return pmSubtractionCalculateEquationStamp(stamps, kernels, index); 813 } 814 815 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels, int index) 809 816 { 810 817 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 833 840 psAssert(stamp->status == PM_SUBTRACTION_STAMP_CALCULATE, "We only operate on stamps with this state."); 834 841 835 // Generate convolutions: these are generated once and saved 836 if (!pmSubtractionConvolveStamp(stamp, kernels, footprint)) { 837 psError(psErrorCodeLast(), false, "Unable to convolve stamp %d.", index); 838 return NULL; 839 } 840 841 #ifdef TESTING 842 for (int j = 0; j < numKernels; j++) { 843 if (stamp->convolutions1) { 844 psString convName = NULL; 845 psStringAppend(&convName, "conv1_%03d_%03d.fits", index, j); 846 psFits *fits = psFitsOpen(convName, "w"); 847 psFree(convName); 848 psKernel *conv = stamp->convolutions1->data[j]; 849 psFitsWriteImage(fits, NULL, conv->image, 0, NULL); 850 psFitsClose(fits); 851 } 852 853 if (stamp->convolutions2) { 854 psString convName = NULL; 855 psStringAppend(&convName, "conv2_%03d_%03d.fits", index, j); 856 psFits *fits = psFitsOpen(convName, "w"); 857 psFree(convName); 858 psKernel *conv = stamp->convolutions2->data[j]; 859 psFitsWriteImage(fits, NULL, conv->image, 0, NULL); 860 psFitsClose(fits); 861 } 862 } 863 #endif 864 865 // XXX visualize the set of convolved stamps 866 867 psImage *polyValues = p_pmSubtractionPolynomial(NULL, spatialOrder, 868 stamp->xNorm, stamp->yNorm); // Polynomial terms 869 870 bool new = stamp->vector ? false : true; // Is this a new run? 842 psImage *polyValues = p_pmSubtractionPolynomial(NULL, spatialOrder, stamp->xNorm, stamp->yNorm); // Polynomial terms 843 844 // Is this a new run? Have we allocated the correct sized vector/matrix? 845 bool new = stamp->vector ? false : true; 846 if (!new && (stamp->vector->n != numParams)) { 847 psFree (stamp->vector); 848 psFree (stamp->matrix); 849 new = true; 850 } 851 871 852 if (new) { 872 853 stamp->matrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); … … 941 922 } 942 923 943 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels, 944 const pmSubtractionEquationCalculationMode mode) 924 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels) 945 925 { 946 926 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 953 933 for (int i = 0; i < stamps->num; i++) { 954 934 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 935 955 936 if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE) { 956 937 continue; … … 969 950 psArrayAdd(job->args, 1, (pmSubtractionKernels*)kernels); // Casting away const to put on array 970 951 PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32); 971 PS_ARRAY_ADD_SCALAR(job->args, mode, PS_TYPE_S32);972 952 if (!psThreadJobAddPending(job)) { 973 953 return false; 974 954 } 975 955 } else { 976 pmSubtractionCalculateEquationStamp(stamps, kernels, i , mode);956 pmSubtractionCalculateEquationStamp(stamps, kernels, i); 977 957 } 978 958 } … … 983 963 } 984 964 985 pmSubtractionVisualPlotLeastSquares(stamps);986 965 pmSubtractionVisualShowKernels((pmSubtractionKernels *)kernels); 987 966 pmSubtractionVisualShowBasis(stamps); 988 989 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate equation: %f sec", 990 psTimerClear("pmSubtractionCalculateEquation")); 991 967 pmSubtractionVisualPlotLeastSquares(stamps); 968 969 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate equation: %f sec", psTimerClear("pmSubtractionCalculateEquation")); 992 970 993 971 return true; … … 998 976 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header); 999 977 1000 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U); 1001 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt); 1002 1003 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask); 1004 1005 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B); 1006 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB); 1007 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB); 1008 1009 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x); 1010 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y); 1011 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 1012 1013 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w); 1014 1015 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 1016 1017 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, 1018 const pmSubtractionStampList *stamps, 1019 const pmSubtractionEquationCalculationMode mode) 978 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) 1020 979 { 1021 980 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); 1022 981 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); 982 983 psTimerStart("pmSubtractionSolveEquation"); 1023 984 1024 985 // Check inputs … … 1042 1003 } 1043 1004 1005 if (stamp->vector->n != numParams) { 1006 fprintf (stderr, "mismatch length\n"); 1007 } 1044 1008 PS_ASSERT_VECTOR_NON_NULL(stamp->vector, false); 1045 1009 PS_ASSERT_VECTOR_SIZE(stamp->vector, (long)numParams, false); … … 1080 1044 } 1081 1045 1046 pmSubtractionVisualPlotLeastSquaresResid(stamps, sumMatrix, numStamps); 1047 1082 1048 #if 0 1083 1049 psImage *save = psImageCopy(NULL, sumMatrix, PS_TYPE_F32); … … 1087 1053 #endif 1088 1054 1055 // XXX TEST : print the matrix & vector 1056 if (0) { 1057 for (int iy = 0; iy < sumMatrix->numRows; iy++) { 1058 for (int ix = 0; ix < sumMatrix->numCols; ix++) { 1059 fprintf (stderr, "%e ", sumMatrix->data.F64[iy][ix]); 1060 } 1061 fprintf (stderr, " : %e\n", sumVector->data.F64[iy]); 1062 } 1063 } 1064 1065 psImage *invMatrix = NULL; 1089 1066 psVector *solution = NULL; // Solution to equation! 1090 1067 solution = psVectorAlloc(numParams, PS_TYPE_F64); … … 1094 1071 // solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1095 1072 // SINGLE solution 1096 if (1) { 1097 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1098 } else { 1099 psVector *PERM = NULL; 1100 psImage *LU = psMatrixLUDecomposition(NULL, &PERM, sumMatrix); 1101 solution = psMatrixLUSolution(solution, LU, sumVector, PERM); 1102 psFree (LU); 1103 psFree (PERM); 1104 } 1073 # if (1) 1074 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, 1e-10); 1075 invMatrix = psMatrixInvert(NULL, sumMatrix, NULL); 1076 # endif 1077 # if (0) 1078 psMatrixLUSolve(sumMatrixLU, sumVector); 1079 solution = psMemIncrRefCounter(sumVector); 1080 invMatrix = psMemIncrRefCounter(sumMatrix); 1081 # endif 1082 # if (0) 1083 psMatrixGJSolve(sumMatrix, sumVector); 1084 invMatrix = psMemIncrRefCounter(sumMatrix); 1085 solution = psMemIncrRefCounter(sumVector); 1086 # endif 1105 1087 1106 1088 # if (0) 1107 1089 for (int i = 0; i < solution->n; i++) { 1108 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Single solution %d: %lf \n", i, solution->data.F64[i]);1090 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Single solution %d: %lf +/- %lf\n", i, solution->data.F64[i], sqrt(fabs(invMatrix->data.F64[i][i]))); 1109 1091 } 1110 1092 # endif 1111 1093 1112 if (!kernels->solution1) { 1113 kernels->solution1 = psVectorAlloc(sumVector->n + 2, PS_TYPE_F64); // 1 for norm, 1 for bg 1114 psVectorInit(kernels->solution1, 0.0); 1115 } 1094 // ensure we have a solution vector of the right size 1095 kernels->solution1 = psVectorRecycle(kernels->solution1, sumVector->n + 2, PS_TYPE_F64); // 1 for norm, 1 for bg 1096 kernels->solution1err = psVectorRecycle(kernels->solution1err, sumVector->n + 2, PS_TYPE_F64); // 1 for norm, 1 for bg 1097 psVectorInit(kernels->solution1, 0.0); 1098 psVectorInit(kernels->solution1err, 0.0); 1116 1099 1117 1100 int numKernels = kernels->num; 1118 1101 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 1119 1102 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 1103 1120 1104 for (int i = 0; i < numKernels * numPoly; i++) { 1121 1105 kernels->solution1->data.F64[i] = solution->data.F64[i]; 1106 kernels->solution1err->data.F64[i] = sqrt(invMatrix->data.F64[i][i]); 1122 1107 } 1123 1108 … … 1131 1116 psFree(sumVector); 1132 1117 psFree(sumMatrix); 1118 psFree(invMatrix); 1133 1119 1134 1120 } else { … … 1160 1146 } 1161 1147 1148 pmSubtractionVisualPlotLeastSquaresResid(stamps, sumMatrix, numStamps); 1149 1162 1150 #if 0 1163 1151 psImage *save = psImageCopy(NULL, sumMatrix, PS_TYPE_F32); … … 1171 1159 } 1172 1160 1161 // XXX TEST : print the matrix & vector 1162 if (0) { 1163 for (int iy = 0; iy < sumMatrix->numRows; iy++) { 1164 for (int ix = 0; ix < sumMatrix->numCols; ix++) { 1165 fprintf (stderr, "%e ", sumMatrix->data.F64[iy][ix]); 1166 } 1167 fprintf (stderr, " : %e\n", sumVector->data.F64[iy]); 1168 } 1169 } 1170 1171 psImage *invMatrix = NULL; 1173 1172 psVector *solution = NULL; // Solution to equation! 1174 1173 solution = psVectorAlloc(numParams, PS_TYPE_F64); … … 1176 1175 1177 1176 // DUAL solution 1178 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1177 # if (1) 1178 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, 1e-10); 1179 invMatrix = psMatrixInvert(NULL, sumMatrix, NULL); 1180 # endif 1181 # if (0) 1182 psMatrixLUSolve(sumMatrix, sumVector); 1183 solution = psMemIncrRefCounter(sumVector); 1184 invMatrix = psMemIncrRefCounter(sumMatrix); 1185 # endif 1179 1186 1180 1187 #if (0) 1181 1188 for (int i = 0; i < solution->n; i++) { 1182 fprintf(stderr, "Dual solution %d: %lf \n", i, solution->data.F64[i]);1189 fprintf(stderr, "Dual solution %d: %lf +/- %lf\n", i, solution->data.F64[i], sqrt(invMatrix->data.F64[i][i])); 1183 1190 } 1184 1191 #endif 1185 1192 1186 if (!kernels->solution1) { 1187 kernels->solution1 = psVectorAlloc(numSolution1 + 2, PS_TYPE_F64); 1188 psVectorInit (kernels->solution1, 0.0); 1189 } 1190 if (!kernels->solution2) { 1191 kernels->solution2 = psVectorAlloc(numSolution2, PS_TYPE_F64); 1192 psVectorInit (kernels->solution2, 0.0); 1193 } 1193 // XXX TEST: manually set the coeffs to a desired solution 1194 // solution->data.F64[0] = +1.826; 1195 // solution->data.F64[1] = -0.115; 1196 // solution->data.F64[2] = 0.0; 1197 // solution->data.F64[3] = 0.0; 1198 1199 // ensure we have solution vectors of the right size 1200 kernels->solution1 = psVectorRecycle(kernels->solution1, numSolution1 + 2, PS_TYPE_F64); // 1 for norm, 1 for bg 1201 kernels->solution1err = psVectorRecycle(kernels->solution1err, numSolution1 + 2, PS_TYPE_F64); // 1 for norm, 1 for bg 1202 kernels->solution2 = psVectorRecycle(kernels->solution2, numSolution2, PS_TYPE_F64); // 1 for norm, 1 for bg 1203 kernels->solution2err = psVectorRecycle(kernels->solution2err, numSolution2, PS_TYPE_F64); // 1 for norm, 1 for bg 1204 1205 psVectorInit(kernels->solution1, 0.0); 1206 psVectorInit(kernels->solution1err, 0.0); 1207 psVectorInit(kernels->solution2, 0.0); 1208 psVectorInit(kernels->solution2err, 0.0); 1194 1209 1195 1210 // for DUAL convolution analysis, we apply the normalization to I1 as follows: … … 1205 1220 kernels->solution1->data.F64[i] = solution->data.F64[i] * stamps->normValue; 1206 1221 kernels->solution2->data.F64[i] = solution->data.F64[i + numSolution1]; 1222 1223 kernels->solution1err->data.F64[i] = sqrt(invMatrix->data.F64[i][i]) * stamps->normValue; 1224 int i2 = i + numSolution1; 1225 kernels->solution2err->data.F64[i] = sqrt(invMatrix->data.F64[i2][i2]); 1207 1226 } 1208 1227 … … 1213 1232 kernels->solution1->data.F64[bgIndex] = 0.0; 1214 1233 1234 psFree(solution); 1235 psFree(sumVector); 1215 1236 psFree(sumMatrix); 1216 psFree(sumVector); 1217 psFree(solution); 1237 psFree(invMatrix); 1218 1238 } 1219 1239 … … 1224 1244 if (psTraceGetLevel("psModules.imcombine") >= 7) { 1225 1245 for (int i = 0; i < kernels->solution1->n; i++) { 1226 psTrace("psModules.imcombine", 7, "Solution 1 %d: %f \n", i, kernels->solution1->data.F64[i]);1246 psTrace("psModules.imcombine", 7, "Solution 1 %d: %f +/- %f\n", i, kernels->solution1->data.F64[i], kernels->solution1err->data.F64[i]); 1227 1247 } 1228 1248 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1229 1249 for (int i = 0; i < kernels->solution2->n; i++) { 1230 psTrace("psModules.imcombine", 7, "Solution 2 %d: %f \n", i, kernels->solution2->data.F64[i]);1250 psTrace("psModules.imcombine", 7, "Solution 2 %d: %f +/- %f\n", i, kernels->solution2->data.F64[i], kernels->solution2err->data.F64[i]); 1231 1251 } 1232 1252 } 1233 1253 } 1254 1255 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Solve equation: %f sec", psTimerClear("pmSubtractionSolveEquation")); 1234 1256 1235 1257 // pmSubtractionVisualPlotLeastSquares((pmSubtractionStampList *) stamps); //casting away const … … 1283 1305 } 1284 1306 1285 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, 1286 pmSubtractionKernels *kernels) 1307 // given the convolved image(s) and the residual image, calculate the second moment(s) and the chisq 1308 bool pmSubtractionChisqStats(psVector *fluxesVector, psVector *chisqDVector, psVector *chisqRVector, psVector *momentVector, psVector *stampMask, psKernel *convolved1, psKernel *convolved2, psKernel *difference, psKernel *residual, psKernel *weight, psKernel *window) { 1309 1310 # ifndef USE_WEIGHT 1311 psAssert(weight == NULL, "impossible!"); 1312 # endif 1313 # ifndef USE_WINDOW 1314 psAssert(window == NULL, "impossible!"); 1315 # endif 1316 1317 int npix = 0; 1318 float chisqR = 0; 1319 float chisqD = 0; 1320 1321 // get the chisq 1322 for (int y = residual->yMin; y <= residual->yMax; y++) { 1323 for (int x = residual->xMin; x <= residual->xMax; x++) { 1324 float valueR = PS_SQR(residual->kernel[y][x]); 1325 if (weight) { 1326 valueR *= weight->kernel[y][x]; 1327 } 1328 // XXX NOTE: do NOT apply the window to the chisq portions of the calculation (that would bias the chisq) 1329 chisqR += valueR; 1330 1331 float valueD = PS_SQR(difference->kernel[y][x]); 1332 if (weight) { 1333 valueD *= weight->kernel[y][x]; 1334 } 1335 chisqD += valueD; 1336 npix ++; 1337 } 1338 } 1339 psVectorAppend(chisqRVector, chisqR / npix); 1340 psVectorAppend(chisqDVector, chisqD / npix); 1341 1342 float value1 = 0; 1343 float value2 = 0; 1344 float flux2 = 0; 1345 float fluxX = 0; 1346 float fluxY = 0; 1347 float fluxX2 = 0; 1348 float fluxY2 = 0; 1349 1350 float fluxC1 = 0; 1351 float fluxC2 = 0; 1352 1353 float moment = 0; 1354 1355 // get the moments from convolved1 1356 if (convolved1) { 1357 for (int y = residual->yMin; y <= residual->yMax; y++) { 1358 for (int x = residual->xMin; x <= residual->xMax; x++) { 1359 value1 = convolved1->kernel[y][x]; 1360 value2 = PS_SQR(value1); 1361 1362 if (window) { 1363 value1 *= window->kernel[y][x]; 1364 value2 *= window->kernel[y][x]; 1365 } 1366 1367 fluxC1 += value1; 1368 flux2 += value2; 1369 fluxX += x * value2; 1370 fluxY += y * value2; 1371 // fluxX2 += PS_SQR(x) * value2; 1372 // fluxY2 += PS_SQR(y) * value2; 1373 fluxX2 += PS_SQR(x) * value1; 1374 fluxY2 += PS_SQR(y) * value1; 1375 } 1376 } 1377 // float Mx = fluxX / flux2; 1378 // float My = fluxY / flux2; 1379 // float Mxx = fluxX2 / flux2; 1380 // float Myy = fluxY2 / flux2; 1381 float Mxx = fluxX2 / fluxC1; 1382 float Myy = fluxY2 / fluxC1; 1383 1384 // fprintf (stderr, "conv1, flux2: %f, Mx: %f, My: %f, Mxx: %f, Myy: %f, chisq: %f, npix: %d\n", flux2, Mx, My, Mxx, Myy, chisq, npix); 1385 moment += Mxx + Myy; 1386 } 1387 1388 // get the moments from convolved1 1389 if (convolved2) { 1390 for (int y = residual->yMin; y <= residual->yMax; y++) { 1391 for (int x = residual->xMin; x <= residual->xMax; x++) { 1392 value1 = convolved2->kernel[y][x]; 1393 value2 = PS_SQR(value1); 1394 1395 // XXX NOTE: do NOT apply the weight to the moments calculation 1396 if (false && weight) { 1397 value2 *= weight->kernel[y][x]; 1398 } 1399 if (window) { 1400 value1 *= window->kernel[y][x]; 1401 value2 *= window->kernel[y][x]; 1402 } 1403 1404 fluxC2 += value1; 1405 flux2 += value2; 1406 fluxX += x * value2; 1407 fluxY += y * value2; 1408 // fluxX2 += PS_SQR(x) * value2; 1409 // fluxY2 += PS_SQR(y) * value2; 1410 fluxX2 += PS_SQR(x) * value1; 1411 fluxY2 += PS_SQR(y) * value1; 1412 } 1413 } 1414 // float Mx = fluxX / flux2; 1415 // float My = fluxY / flux2; 1416 // float Mxx = fluxX2 / flux2; 1417 // float Myy = fluxY2 / flux2; 1418 float Mxx = fluxX2 / fluxC2; 1419 float Myy = fluxY2 / fluxC2; 1420 1421 // fprintf (stderr, "conv2, flux2: %f, Mx: %f, My: %f, Mxx: %f, Myy: %f, chisq: %f, npix: %d\n", flux2, Mx, My, Mxx, Myy, chisq, npix); 1422 moment += Mxx + Myy; 1423 } 1424 1425 float flux = fluxC1 + fluxC2; 1426 1427 if (convolved1 && convolved2) { 1428 moment *= 0.5; 1429 flux *= 0.5; 1430 } 1431 psVectorAppend(momentVector, moment); 1432 psVectorAppend(fluxesVector, flux); 1433 1434 // check that the last appended values are ok: 1435 int Nelem = fluxesVector->n - 1; 1436 bool valid = true; 1437 valid &= isfinite(chisqRVector->data.F32[Nelem]); 1438 valid &= isfinite(fluxesVector->data.F32[Nelem]); 1439 valid &= isfinite(momentVector->data.F32[Nelem]); 1440 if (valid) { 1441 psVectorAppend(stampMask, 0); 1442 } else { 1443 psVectorAppend(stampMask, 0x02); 1444 } 1445 return true; 1446 } 1447 1448 bool pmSubtractionCalculateChisqAndMoments(pmSubtractionQuality **bestMatch, 1449 pmSubtractionStampList *stamps, 1450 pmSubtractionKernels *kernels) 1287 1451 { 1288 1452 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL); 1289 1453 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, NULL); 1290 1454 PM_ASSERT_SUBTRACTION_KERNELS_SOLUTION(kernels, NULL); 1455 1456 psTimerStart("pmSubtractionCalculateChisqAndMoments"); 1457 1458 // XXX need to save these somewhere 1459 psVector *fluxes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1460 psVector *chisqD = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1461 psVector *chisqR = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1462 psVector *moments = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1463 psVector *stampMask = psVectorAllocEmpty(stamps->num, PS_TYPE_VECTOR_MASK); 1464 1465 int footprint = stamps->footprint; // Half-size of stamps 1466 int numKernels = kernels->num; // Number of kernels 1467 1468 psImage *polyValues = NULL; // Polynomial values 1469 1470 // storage for the image (convolved2 is not used in SINGLE mode) 1471 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1472 psKernel *difference = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1473 psKernel *convolved1 = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1474 psKernel *convolved2 = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1475 1476 int nGood = 0; 1477 for (int i = 0; i < stamps->num; i++) { 1478 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest 1479 if (stamp->status != PM_SUBTRACTION_STAMP_USED) { 1480 // mark this stamp as unused (note that we have to append NANs to the other vectors to keep the lengths in sync) 1481 psVectorAppend(moments, NAN); 1482 psVectorAppend(fluxes, NAN); 1483 psVectorAppend(chisqD, NAN); 1484 psVectorAppend(chisqR, NAN); 1485 psVectorAppend(stampMask, 0x01); 1486 continue; 1487 } 1488 nGood ++; 1489 1490 // Calculate coefficients of the kernel basis functions 1491 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm); 1492 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 1493 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background 1494 1495 // Calculate residuals 1496 psImageInit(residual->image, 0.0); 1497 psImageInit(difference->image, 0.0); 1498 1499 psKernel *weight = NULL; 1500 psKernel *window = NULL; 1501 1502 #ifdef USE_WEIGHT 1503 weight = stamp->weight; 1504 #endif 1505 #ifdef USE_WINDOW 1506 window = stamps->window; 1507 #endif 1508 1509 if (kernels->mode != PM_SUBTRACTION_MODE_DUAL) { 1510 1511 // the single-direction psf match code attempts to find the kernel such that: 1512 // source * kernel = target. we need to assign 'source' and 'target' correctly 1513 // depending on which of image1 or image2 we asked to be convolved. 1514 1515 psKernel *target; // Target postage stamp (convolve source to match the target) 1516 psKernel *source; // Source postage stamp (convolve source to match the target) 1517 psArray *convolutions; // Convolution postage stamps for each kernel basis function 1518 1519 // init the accumulation image 1520 psImageInit(convolved1->image, 0.0); 1521 1522 switch (kernels->mode) { 1523 case PM_SUBTRACTION_MODE_1: 1524 target = stamp->image2; 1525 source = stamp->image1; 1526 convolutions = stamp->convolutions1; 1527 break; 1528 case PM_SUBTRACTION_MODE_2: 1529 target = stamp->image1; 1530 source = stamp->image2; 1531 convolutions = stamp->convolutions2; 1532 break; 1533 default: 1534 psAbort("Unsupported subtraction mode: %x", kernels->mode); 1535 } 1536 1537 // generate the convolved source image (sum over kernels) 1538 for (int j = 0; j < numKernels; j++) { 1539 psKernel *convolution = convolutions->data[j]; // Convolution 1540 double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1541 for (int y = - footprint; y <= footprint; y++) { 1542 for (int x = - footprint; x <= footprint; x++) { 1543 convolved1->kernel[y][x] += convolution->kernel[y][x] * coefficient; 1544 } 1545 } 1546 } 1547 1548 // Generate the difference, residual, and convolved source images. Note the we 1549 // accumulate the convolution of (A-B), so we need to replace it to generate the 1550 // images of the convolved source image. 1551 for (int y = - footprint; y <= footprint; y++) { 1552 for (int x = - footprint; x <= footprint; x++) { 1553 difference->kernel[y][x] = target->kernel[y][x] - source->kernel[y][x] * norm - background; 1554 residual->kernel[y][x] = difference->kernel[y][x] - convolved1->kernel[y][x]; 1555 convolved1->kernel[y][x] += source->kernel[y][x] * norm; 1556 } 1557 } 1558 1559 // XXX if we want to have a weight and window, we'll need to pass through to here 1560 pmSubtractionChisqStats(fluxes, chisqD, chisqR, moments, stampMask, convolved1, NULL, difference, residual, weight, window); 1561 1562 } else { 1563 1564 // Dual convolution 1565 psArray *convolutions1 = stamp->convolutions1; // Convolutions of the first image 1566 psArray *convolutions2 = stamp->convolutions2; // Convolutions of the second image 1567 psKernel *image1 = stamp->image1; // The first image 1568 psKernel *image2 = stamp->image2; // The second image 1569 1570 // init the accumulation images 1571 psImageInit(convolved1->image, 0.0); 1572 psImageInit(convolved2->image, 0.0); 1573 1574 for (int j = 0; j < numKernels; j++) { 1575 psKernel *conv1 = convolutions1->data[j]; // Convolution of first image 1576 psKernel *conv2 = convolutions2->data[j]; // Convolution of second image 1577 double coeff1 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1 1578 double coeff2 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, true); // Coefficient 2 1579 1580 for (int y = - footprint; y <= footprint; y++) { 1581 for (int x = - footprint; x <= footprint; x++) { 1582 // NOTE sign for coeff2 1583 convolved1->kernel[y][x] += +conv1->kernel[y][x] * coeff1; 1584 convolved2->kernel[y][x] += -conv2->kernel[y][x] * coeff2; 1585 } 1586 } 1587 } 1588 1589 // Generate the difference, residual, and convolved source images. Note the we 1590 // accumulate the convolutions of (A-B), so we need to replace (A or B) to generate 1591 // the images of the convolved source images. 1592 for (int y = - footprint; y <= footprint; y++) { 1593 for (int x = - footprint; x <= footprint; x++) { 1594 difference->kernel[y][x] = image2->kernel[y][x] - image1->kernel[y][x] * norm - background; 1595 residual->kernel[y][x] = difference->kernel[y][x] + convolved2->kernel[y][x] - convolved1->kernel[y][x]; 1596 convolved1->kernel[y][x] += image1->kernel[y][x] * norm; 1597 convolved2->kernel[y][x] += image2->kernel[y][x]; 1598 } 1599 } 1600 1601 if (0) { 1602 psFitsWriteImageSimple("conv1.fits", convolved1->image, NULL); 1603 psFitsWriteImageSimple("conv2.fits", convolved2->image, NULL); 1604 psFitsWriteImageSimple("resid.fits", residual->image, NULL); 1605 pmVisualAskUser(NULL); 1606 } 1607 1608 pmSubtractionChisqStats(fluxes, chisqD, chisqR, moments, stampMask, convolved1, convolved2, difference, residual, weight, window); 1609 } 1610 } 1611 1612 // find the mean chisq and mean moment 1613 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN); 1614 psVectorStats (stats, chisqD, NULL, stampMask, 0xff); 1615 float chisqDValue = stats->sampleMean; 1616 1617 psStatsInit(stats); 1618 psVectorStats (stats, chisqR, NULL, stampMask, 0xff); 1619 float chisqRValue = stats->sampleMean; 1620 1621 psStatsInit(stats); 1622 psVectorStats (stats, moments, NULL, stampMask, 0xff); 1623 float momentValue = stats->sampleMean; 1624 1625 double sumKernel1 = 0.0, sumKernel2 = 0.0; // Sum of the kernel 1626 1627 // calculate the variance contribution from this smoothing kernel 1628 psKernel *modelKernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); 1629 for (int y = modelKernel->yMin; y <= modelKernel->yMax; y++) { 1630 for (int x = modelKernel->xMin; x <= modelKernel->xMax; x++) { 1631 if (!isfinite(modelKernel->kernel[y][x])) { 1632 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Non-finite covariance matrix element in kernel at %d,%d", x, y); 1633 return NULL; 1634 } 1635 sumKernel1 += PS_SQR(modelKernel->kernel[y][x]); 1636 } 1637 } 1638 psFree (modelKernel); 1639 1640 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1641 psKernel *modelKernel = pmSubtractionKernel(kernels, 0.0, 0.0, true); 1642 for (int y = modelKernel->yMin; y <= modelKernel->yMax; y++) { 1643 for (int x = modelKernel->xMin; x <= modelKernel->xMax; x++) { 1644 if (!isfinite(modelKernel->kernel[y][x])) { 1645 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Non-finite covariance matrix element in kernel at %d,%d", x, y); 1646 return NULL; 1647 } 1648 sumKernel2 += PS_SQR(modelKernel->kernel[y][x]); 1649 } 1650 } 1651 psFree (modelKernel); 1652 } else { 1653 sumKernel2 = 1.0; 1654 } 1655 1656 // if we modify the chisq value by the (sumKernel1 + sumKernel2), we account for the 1657 // smoothing coming from larger kernels adding additional spatial fit terms should be 1658 // penalized by increasing the score somewhat. the 0.01 value is not well-chosen. 1659 float orderFactor = 0.01 * kernels->spatialOrder; 1660 float score = 2.0 * chisqRValue / (sumKernel1 + sumKernel2) + orderFactor; 1661 psLogMsg("psModules.imcombine", PS_LOG_INFO, "chisq: %6.3f, chisqD: %6.3f, moment: %6.3f, sumKernel_1: %6.3f, sumKernel_2, score: %6.3f: %6.3f\n", chisqRValue, chisqDValue, momentValue, sumKernel1, sumKernel2, score); 1662 1663 // save this result if it is the first or the best (skip if bestMatch is NULL) 1664 if (bestMatch) { 1665 pmSubtractionQuality *match = *bestMatch; 1666 bool keep = false; 1667 if (match == NULL) { 1668 *bestMatch = match = pmSubtractionQualityAlloc(); 1669 keep = true; 1670 } else { 1671 if (score < match->score) { 1672 psFree(match->fluxes); 1673 psFree(match->chisq); 1674 psFree(match->moments); 1675 psFree(match->stampMask); 1676 keep = true; 1677 } 1678 } 1679 if (keep) { 1680 psLogMsg("psModules.imcombine", PS_LOG_INFO, "keeping order: %d, mode: %d, score: %f\n", kernels->spatialOrder, kernels->mode, score); 1681 match->score = score; 1682 match->spatialOrder = kernels->spatialOrder; 1683 match->mode = kernels->mode; 1684 match->nGood = nGood; 1685 match->fluxes = psMemIncrRefCounter(fluxes); 1686 match->chisq = psMemIncrRefCounter(chisqR); 1687 match->moments = psMemIncrRefCounter(moments); 1688 match->stampMask = psMemIncrRefCounter(stampMask); 1689 } 1690 } 1691 1692 pmSubtractionVisualPlotChisqAndMoments(fluxes, chisqR, moments); 1693 1694 psFree(stats); 1695 psFree(chisqR); 1696 psFree(chisqD); 1697 psFree(fluxes); 1698 psFree(moments); 1699 psFree(stampMask); 1700 1701 psFree(residual); 1702 psFree(difference); 1703 psFree(convolved1); 1704 psFree(convolved2); 1705 psFree(polyValues); 1706 1707 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate Chisq and Moments: %f sec", psTimerClear("pmSubtractionCalculateChisqAndMoments")); 1708 1709 return true; 1710 } 1711 1712 // XXX for now, let's not use this, and let's instead just use values from pmSubtractionCalculateChisqAndMoments 1713 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels) 1714 { 1715 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL); 1716 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, NULL); 1717 PM_ASSERT_SUBTRACTION_KERNELS_SOLUTION(kernels, NULL); 1718 1719 psTimerStart("pmSubtractionCalculateDeviations"); 1291 1720 1292 1721 psVector *deviations = psVectorAlloc(stamps->num, PS_TYPE_F32); // Mean deviation for stamps … … 1298 1727 psImage *polyValues = NULL; // Polynomial values 1299 1728 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1300 1301 // set up holding images for the visualization1302 pmSubtractionVisualShowFitInit (stamps);1303 1729 1304 1730 psVector *fResSigma = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); … … 1401 1827 } 1402 1828 1403 // XXX visualize the target, source, convolution and residual1404 pmSubtractionVisualShowFitAddStamp (target, source, residual, background, norm, i);1405 1406 1829 for (int y = - footprint; y <= footprint; y++) { 1407 1830 for (int x = - footprint; x <= footprint; x++) { … … 1438 1861 } 1439 1862 1440 // XXX visualize the target, source, convolution and residual1441 pmSubtractionVisualShowFitAddStamp (image2, image1, residual, background, norm, i);1442 1443 1863 for (int y = - footprint; y <= footprint; y++) { 1444 1864 for (int x = - footprint; x <= footprint; x++) { … … 1455 1875 } 1456 1876 1877 double flux = 0.0; 1457 1878 double deviation = 0.0; // Sum of differences 1458 1879 for (int y = - footprint; y <= footprint; y++) { … … 1460 1881 double dev = PS_SQR(residual->kernel[y][x]) * weight->kernel[y][x]; 1461 1882 deviation += dev; 1462 #ifdef TESTING 1463 residual->kernel[y][x] = dev; 1464 #endif 1883 flux += stamp->image1->kernel[y][x] + stamp->image2->kernel[y][x]; 1465 1884 } 1466 1885 } 1467 1886 deviations->data.F32[i] = devNorm * deviation; 1468 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d):%f\n",1469 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i] );1887 psTrace("psModules.imcombine", 5, "Deviation and Flux for stamp %d (%d,%d): %f %f\n", 1888 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i], flux); 1470 1889 psStringAppend(&log, "Stamp %d (%d,%d): %f\n", 1471 1890 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i]); 1472 1891 if (!isfinite(deviations->data.F32[i])) { 1473 1892 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 1474 psTrace("psModules.imcombine", 5, 1475 "Rejecting stamp %d (%d,%d) because of non-finite deviation\n", 1476 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 1893 psTrace("psModules.imcombine", 5, "Rejecting stamp %d (%d,%d) because of non-finite deviation\n", i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 1477 1894 continue; 1478 1895 } 1479 1480 #ifdef TESTING1481 {1482 psString filename = NULL;1483 psStringAppend(&filename, "resid_%03d.fits", i);1484 psFits *fits = psFitsOpen(filename, "w");1485 psFree(filename);1486 psFitsWriteImage(fits, NULL, residual->image, 0, NULL);1487 psFitsClose(fits);1488 }1489 if (stamp->image1) {1490 psString filename = NULL;1491 psStringAppend(&filename, "stamp_image1_%03d.fits", i);1492 psFits *fits = psFitsOpen(filename, "w");1493 psFree(filename);1494 psFitsWriteImage(fits, NULL, stamp->image1->image, 0, NULL);1495 psFitsClose(fits);1496 }1497 if (stamp->image2) {1498 psString filename = NULL;1499 psStringAppend(&filename, "stamp_image2_%03d.fits", i);1500 psFits *fits = psFitsOpen(filename, "w");1501 psFree(filename);1502 psFitsWriteImage(fits, NULL, stamp->image2->image, 0, NULL);1503 psFitsClose(fits);1504 }1505 if (stamp->weight) {1506 psString filename = NULL;1507 psStringAppend(&filename, "stamp_weight_%03d.fits", i);1508 psFits *fits = psFitsOpen(filename, "w");1509 psFree(filename);1510 psFitsWriteImage(fits, NULL, stamp->weight->image, 0, NULL);1511 psFitsClose(fits);1512 }1513 #endif1514 1515 1896 } 1516 1897 1517 1898 psFree(keepStamps); 1518 1899 1519 psLogMsg("psModules.imcombine", PS_LOG_ DETAIL, "%s", log);1900 psLogMsg("psModules.imcombine", PS_LOG_MINUTIA, "%s", log); 1520 1901 psFree(log); 1521 1902 … … 1527 1908 psLogMsg("psModules.imcombine", PS_LOG_INFO, "normalization: %f, background: %f", norm, background); 1528 1909 1529 pmSubtractionVisualShowFit(norm);1530 pmSubtractionVisualPlotFit(kernels);1531 1532 1910 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 1533 1911 psVectorStats (stats, fResSigma, NULL, NULL, 0); … … 1560 1938 psFree(polyValues); 1561 1939 1940 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate Deviations: %f sec", psTimerClear("pmSubtractionCalculateDeviations")); 1941 1562 1942 return deviations; 1563 }1564 1565 // we are supplied U, not Ut; w represents a diagonal matrix (also, we apply 1/w instead of w)1566 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U) {1567 1568 psAssert (w->n == U->numCols, "w and U dimensions do not match");1569 1570 // wUt has dimensions transposed relative to Ut.1571 psImage *wUt = psImageAlloc (U->numRows, U->numCols, PS_TYPE_F64);1572 psImageInit (wUt, 0.0);1573 1574 for (int i = 0; i < wUt->numCols; i++) {1575 for (int j = 0; j < wUt->numRows; j++) {1576 if (!isfinite(w->data.F64[j])) continue;1577 if (w->data.F64[j] == 0.0) continue;1578 wUt->data.F64[j][i] = U->data.F64[i][j] / w->data.F64[j];1579 }1580 }1581 return wUt;1582 }1583 1584 // XXX this is just standard matrix multiplication: use psMatrixMultiply?1585 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt) {1586 1587 psAssert (V->numCols == wUt->numRows, "matrix dimensions do not match");1588 1589 psImage *Ainv = psImageAlloc (wUt->numCols, V->numRows, PS_TYPE_F64);1590 1591 for (int i = 0; i < Ainv->numCols; i++) {1592 for (int j = 0; j < Ainv->numRows; j++) {1593 double sum = 0.0;1594 for (int k = 0; k < V->numCols; k++) {1595 sum += V->data.F64[j][k] * wUt->data.F64[k][i];1596 }1597 Ainv->data.F64[j][i] = sum;1598 }1599 }1600 return Ainv;1601 }1602 1603 // we are supplied U, not Ut1604 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B) {1605 1606 psAssert (U->numRows == B->n, "U and B dimensions do not match");1607 1608 UtB[0] = psVectorRecycle (UtB[0], U->numCols, PS_TYPE_F64);1609 1610 for (int i = 0; i < U->numCols; i++) {1611 double sum = 0.0;1612 for (int j = 0; j < U->numRows; j++) {1613 sum += B->data.F64[j] * U->data.F64[j][i];1614 }1615 UtB[0]->data.F64[i] = sum;1616 }1617 return true;1618 }1619 1620 // w is diagonal1621 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB) {1622 1623 psAssert (w->n == UtB->n, "w and UtB dimensions do not match");1624 1625 // wUt has dimensions transposed relative to Ut.1626 wUtB[0] = psVectorRecycle (wUtB[0], w->n, PS_TYPE_F64);1627 psVectorInit (wUtB[0], 0.0);1628 1629 for (int i = 0; i < w->n; i++) {1630 if (!isfinite(w->data.F64[i])) continue;1631 if (w->data.F64[i] == 0.0) continue;1632 wUtB[0]->data.F64[i] = UtB->data.F64[i] / w->data.F64[i];1633 }1634 return true;1635 }1636 1637 // this is basically matrix * vector1638 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB) {1639 1640 psAssert (V->numCols == wUtB->n, "V and wUtB dimensions do not match");1641 1642 VwUtB[0] = psVectorRecycle (*VwUtB, V->numRows, PS_TYPE_F64);1643 1644 for (int j = 0; j < V->numRows; j++) {1645 double sum = 0.0;1646 for (int i = 0; i < V->numCols; i++) {1647 sum += V->data.F64[j][i] * wUtB->data.F64[i];1648 }1649 VwUtB[0]->data.F64[j] = sum;1650 }1651 return true;1652 }1653 1654 // this is basically matrix * vector1655 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x) {1656 1657 psAssert (A->numCols == x->n, "A and x dimensions do not match");1658 1659 B[0] = psVectorRecycle (*B, A->numRows, PS_TYPE_F64);1660 1661 for (int j = 0; j < A->numRows; j++) {1662 double sum = 0.0;1663 for (int i = 0; i < A->numCols; i++) {1664 sum += A->data.F64[j][i] * x->data.F64[i];1665 }1666 B[0]->data.F64[j] = sum;1667 }1668 return true;1669 }1670 1671 // this is basically Vector * vector1672 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y) {1673 1674 psAssert (x->n == y->n, "x and y dimensions do not match");1675 1676 double sum = 0.0;1677 for (int i = 0; i < x->n; i++) {1678 sum += x->data.F64[i] * y->data.F64[i];1679 }1680 *value = sum;1681 return true;1682 }1683 1684 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) {1685 1686 int footprint = stamps->footprint; // Half-size of stamps1687 1688 double sum = 0.0;1689 for (int i = 0; i < stamps->num; i++) {1690 1691 pmSubtractionStamp *stamp = stamps->stamps->data[i];1692 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue;1693 1694 psKernel *weight = NULL;1695 psKernel *window = NULL;1696 psKernel *input = NULL;1697 1698 #ifdef USE_WEIGHT1699 weight = stamp->weight;1700 #endif1701 #ifdef USE_WINDOW1702 window = stamps->window;1703 #endif1704 1705 switch (kernels->mode) {1706 // MODE_1 : convolve image 1 to match image 2 (and vice versa)1707 case PM_SUBTRACTION_MODE_1:1708 input = stamp->image2;1709 break;1710 case PM_SUBTRACTION_MODE_2:1711 input = stamp->image1;1712 break;1713 default:1714 psAbort ("programming error");1715 }1716 1717 for (int y = - footprint; y <= footprint; y++) {1718 for (int x = - footprint; x <= footprint; x++) {1719 double in = input->kernel[y][x];1720 double value = in*in;1721 if (weight) {1722 float wtVal = weight->kernel[y][x];1723 value *= wtVal;1724 }1725 if (window) {1726 float winVal = window->kernel[y][x];1727 value *= winVal;1728 }1729 sum += value;1730 }1731 }1732 }1733 *y2 = sum;1734 return true;1735 }1736 1737 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) {1738 1739 int footprint = stamps->footprint; // Half-size of stamps1740 int numKernels = kernels->num; // Number of kernels1741 1742 double sum = 0.0;1743 1744 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image1745 psImageInit(residual->image, 0.0);1746 1747 psImage *polyValues = NULL; // Polynomial values1748 1749 for (int i = 0; i < stamps->num; i++) {1750 1751 pmSubtractionStamp *stamp = stamps->stamps->data[i];1752 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue;1753 1754 psKernel *weight = NULL;1755 psKernel *window = NULL;1756 psKernel *target = NULL;1757 psKernel *source = NULL;1758 1759 psArray *convolutions = NULL;1760 1761 #ifdef USE_WEIGHT1762 weight = stamp->weight;1763 #endif1764 #ifdef USE_WINDOW1765 window = stamps->window;1766 #endif1767 1768 switch (kernels->mode) {1769 // MODE_1 : convolve image 1 to match image 2 (and vice versa)1770 case PM_SUBTRACTION_MODE_1:1771 target = stamp->image2;1772 source = stamp->image1;1773 convolutions = stamp->convolutions1;1774 break;1775 case PM_SUBTRACTION_MODE_2:1776 target = stamp->image1;1777 source = stamp->image2;1778 convolutions = stamp->convolutions2;1779 break;1780 default:1781 psAbort ("programming error");1782 }1783 1784 // Calculate coefficients of the kernel basis functions1785 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm);1786 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation1787 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background1788 1789 psImageInit(residual->image, 0.0);1790 for (int j = 0; j < numKernels; j++) {1791 psKernel *convolution = convolutions->data[j]; // Convolution1792 double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient1793 for (int y = - footprint; y <= footprint; y++) {1794 for (int x = - footprint; x <= footprint; x++) {1795 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient;1796 }1797 }1798 }1799 1800 for (int y = - footprint; y <= footprint; y++) {1801 for (int x = - footprint; x <= footprint; x++) {1802 double resid = target->kernel[y][x] - background - source->kernel[y][x] * norm + residual->kernel[y][x];1803 double value = PS_SQR(resid);1804 if (weight) {1805 float wtVal = weight->kernel[y][x];1806 value *= wtVal;1807 }1808 if (window) {1809 float winVal = window->kernel[y][x];1810 value *= winVal;1811 }1812 sum += value;1813 }1814 }1815 }1816 psFree (polyValues);1817 psFree (residual);1818 1819 return sum;1820 }1821 1822 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask) {1823 1824 for (int i = 0; i < w->n; i++) {1825 wApply->data.F64[i] = wMask->data.U8[i] ? 0.0 : w->data.F64[i];1826 }1827 return true;1828 }1829 1830 // we are supplied V and w; w represents a diagonal matrix (also, we apply 1/w instead of w)1831 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w) {1832 1833 psAssert (w->n == V->numCols, "w and U dimensions do not match");1834 1835 psImage *Vn = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64);1836 psImageInit (Vn, 0.0);1837 1838 // generate Vn = V * w^{-1}1839 for (int j = 0; j < Vn->numRows; j++) {1840 for (int i = 0; i < Vn->numCols; i++) {1841 if (!isfinite(w->data.F64[i])) continue;1842 if (w->data.F64[i] == 0.0) continue;1843 Vn->data.F64[j][i] = V->data.F64[j][i] / w->data.F64[i];1844 }1845 }1846 1847 psImage *Xvar = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64);1848 psImageInit (Xvar, 0.0);1849 1850 // generate Xvar = Vn * Vn^T1851 for (int j = 0; j < Vn->numRows; j++) {1852 for (int i = 0; i < Vn->numCols; i++) {1853 double sum = 0.0;1854 for (int k = 0; k < Vn->numCols; k++) {1855 sum += Vn->data.F64[k][i]*Vn->data.F64[k][j];1856 }1857 Xvar->data.F64[j][i] = sum;1858 }1859 }1860 return Xvar;1861 1943 } 1862 1944 … … 1864 1946 // of the elements of an image A(x,y) = A->data.F64[y][x] = A_x,y, a matrix 1865 1947 // multiplication is: A_k,j * B_i,k = C_i,j 1866 1867 1948 1868 1949 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header) { -
trunk/psModules/src/imcombine/pmSubtractionEquation.h
r29543 r30622 4 4 #include "pmSubtractionStamps.h" 5 5 #include "pmSubtractionKernels.h" 6 7 typedef enum { 8 PM_SUBTRACTION_EQUATION_NONE = 0x00, 9 PM_SUBTRACTION_EQUATION_NORM = 0x01, 10 PM_SUBTRACTION_EQUATION_BG = 0x02, 11 PM_SUBTRACTION_EQUATION_KERNELS = 0x04, 12 PM_SUBTRACTION_EQUATION_ALL = 0x07, // value should be NORM | BG | KERNELS 13 } pmSubtractionEquationCalculationMode; 6 #include "pmSubtraction.h" 14 7 15 8 /// Execute a thread job to calculate the least-squares equation for a stamp … … 20 13 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, ///< Stamps 21 14 pmSubtractionKernels *kernels, ///< Kernel parameters 22 int index, ///< Index of stamp 23 const pmSubtractionEquationCalculationMode mode 15 int index ///< Index of stamp 24 16 ); 25 17 26 18 /// Calculate the least-squares equation to match the image quality 27 19 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, ///< Stamps 28 pmSubtractionKernels *kernels, ///< Kernel parameters 29 const pmSubtractionEquationCalculationMode mode 20 pmSubtractionKernels *kernels ///< Kernel parameters 30 21 ); 31 22 32 23 /// Solve the least-squares equation to match the image quality 33 24 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, ///< Kernel parameters 34 const pmSubtractionStampList *stamps, ///< Stamps 35 const pmSubtractionEquationCalculationMode mode 25 const pmSubtractionStampList *stamps ///< Stamps 36 26 ); 37 27 … … 92 82 bool pmSubtractionCalculateMomentsKernel(double *Mxx, double *Myy, psKernel *image, int footprint, int window); 93 83 84 bool pmSubtractionChisqStats(psVector *fluxesVector, psVector *chisqDVector, psVector *chisqRVector, psVector *momentVector, psVector *stampMask, psKernel *convolved1, psKernel *convolved2, psKernel *difference, psKernel *residual, psKernel *weight, psKernel *window); 85 86 bool pmSubtractionCalculateChisqAndMoments(pmSubtractionQuality **bestMatch, pmSubtractionStampList *stamps, pmSubtractionKernels *kernels); 94 87 #endif -
trunk/psModules/src/imcombine/pmSubtractionEquation.v0.c
r29543 r30622 9 9 #include "pmErrorCodes.h" 10 10 #include "pmSubtraction.h" 11 #include "pmSubtractionTypes.h" 11 12 #include "pmSubtractionKernels.h" 12 13 #include "pmSubtractionStamps.h" -
trunk/psModules/src/imcombine/pmSubtractionHermitian.c
r26893 r30622 8 8 #include <pslib.h> 9 9 10 #include "pmSubtractionTypes.h" 10 11 #include "pmSubtractionHermitian.h" 11 12 -
trunk/psModules/src/imcombine/pmSubtractionIO.c
r27321 r30622 12 12 #include "pmConceptsRead.h" 13 13 14 #include "pmSubtractionTypes.h" 14 15 #include "pmSubtraction.h" 15 16 #include "pmSubtractionKernels.h" -
trunk/psModules/src/imcombine/pmSubtractionKernels.c
r29597 r30622 8 8 #include <pslib.h> 9 9 10 #include "pmFPA.h" 11 #include "pmSubtractionTypes.h" 10 12 #include "pmSubtraction.h" 11 13 #include "pmSubtractionKernels.h" … … 20 22 { 21 23 psFree(kernels->description); 24 psFree(kernels->fwhms); 25 psFree(kernels->orders); 22 26 psFree(kernels->u); 23 27 psFree(kernels->v); … … 30 34 psFree(kernels->solution1); 31 35 psFree(kernels->solution2); 36 psFree(kernels->solution1err); 37 psFree(kernels->solution2err); 32 38 psFree(kernels->sampleStamps); 33 39 } … … 419 425 420 426 int num = 0; // Number of basis functions 421 psString params = NULL; // List of parameters422 427 for (int i = 0; i < numGaussians; i++) { 423 428 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 424 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);425 429 num += (gaussOrder + 1) * (gaussOrder + 2) / 2; 426 430 } 427 431 428 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS, size, 429 spatialOrder, penalty, bounds, mode); // Kernels 430 psStringAppend(&kernels->description, "ISIS(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 431 432 psLogMsg("psModules.imcombine", PS_LOG_INFO, "ISIS kernel: %s,%d --> %d elements", 433 params, spatialOrder, num); 434 psFree(params); 432 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS, size, fwhms, orders, spatialOrder, penalty, bounds, mode); // Kernels 433 pmSubtractionKernelsMakeDescription(kernels); 434 psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num); 435 435 436 436 # if (!CENTRAL_DELTA && !ZERO_KERNEL_ZERO_FLUX) … … 503 503 504 504 int num = 0; // Number of basis functions 505 psString params = NULL; // List of parameters506 505 for (int i = 0; i < numGaussians; i++) { 507 506 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 508 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);509 507 num += (gaussOrder + 1) * (gaussOrder + 2) / 2; 510 508 num += (11 - gaussOrder - 1); // include all higher order radial terms 511 509 } 512 510 513 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS_RADIAL, size, 514 spatialOrder, penalty, bounds, mode); // Kernels 515 psStringAppend(&kernels->description, "ISIS_RADIAL(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 516 517 psLogMsg("psModules.imcombine", PS_LOG_INFO, "ISIS_RADIAL kernel: %s,%d --> %d elements", params, spatialOrder, num); 518 psFree(params); 511 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS_RADIAL, size, fwhms, orders, spatialOrder, penalty, bounds, mode); // Kernels 512 pmSubtractionKernelsMakeDescription(kernels); 513 psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num); 519 514 520 515 // Set the kernel parameters … … 569 564 570 565 int num = 0; // Number of basis functions 571 psString params = NULL; // List of parameters572 566 for (int i = 0; i < numGaussians; i++) { 573 567 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 574 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);575 568 num += (gaussOrder + 1) * (gaussOrder + 2) / 2; 576 569 } 577 570 578 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_HERM, size, 579 spatialOrder, penalty, bounds, mode); // Kernels 580 psStringAppend(&kernels->description, "HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 581 582 psLogMsg("psModules.imcombine", PS_LOG_INFO, "HERM kernel: %s,%d --> %d elements", 583 params, spatialOrder, num); 584 psFree(params); 571 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_HERM, size, fwhms, orders, spatialOrder, penalty, bounds, mode); // Kernels 572 pmSubtractionKernelsMakeDescription(kernels); 573 psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num); 585 574 586 575 // Set the kernel parameters … … 627 616 628 617 int num = 0; // Number of basis functions 629 psString params = NULL; // List of parameters630 618 for (int i = 0; i < numGaussians; i++) { 631 619 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 632 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);633 620 num += PS_SQR(gaussOrder + 1); 634 621 } 635 622 636 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_DECONV_HERM, size, 637 spatialOrder, penalty, bounds, mode); // Kernels 638 psStringAppend(&kernels->description, "DECONV_HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 639 640 psLogMsg("psModules.imcombine", PS_LOG_INFO, "DECONVOLVED HERM kernel: %s,%d --> %d elements", params, spatialOrder, num); 641 psFree(params); 623 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_DECONV_HERM, size, fwhms, orders, spatialOrder, penalty, bounds, mode); // Kernels 624 pmSubtractionKernelsMakeDescription(kernels); 625 psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num); 642 626 643 627 // XXXXX hard-wired reference sigma for now of 1.7 pix (== 4.0 pix fwhm == 1.0 arcsec in simtest) … … 713 697 714 698 pmSubtractionKernels *pmSubtractionKernelsAlloc(int numBasisFunctions, pmSubtractionKernelsType type, 715 int size, int spatialOrder, float penalty, psRegion bounds,699 int size, psVector *fwhms, psVector *orders, int spatialOrder, float penalty, psRegion bounds, 716 700 pmSubtractionMode mode) 717 701 { … … 722 706 kernels->description = NULL; 723 707 kernels->num = numBasisFunctions; 708 kernels->fwhms = psMemIncrRefCounter(fwhms); 709 kernels->orders = psMemIncrRefCounter(orders); 724 710 kernels->u = psVectorAlloc(numBasisFunctions, PS_TYPE_S32); 725 711 kernels->v = psVectorAlloc(numBasisFunctions, PS_TYPE_S32); … … 740 726 kernels->size = size; 741 727 kernels->inner = 0; 728 kernels->binning = 0; 729 kernels->ringsOrder = 0; 742 730 kernels->spatialOrder = spatialOrder; 743 731 kernels->bgOrder = 0; … … 745 733 kernels->solution1 = NULL; 746 734 kernels->solution2 = NULL; 735 kernels->solution1err = NULL; 736 kernels->solution2err = NULL; 747 737 kernels->mean = NAN; 748 738 kernels->rms = NAN; … … 823 813 int num = PS_SQR(2 * size + 1) - 1; // Number of basis functions 824 814 825 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(0, PM_SUBTRACTION_KERNEL_POIS, size, 826 spatialOrder, penalty, bounds, mode); // Kernels 827 psStringAppend(&kernels->description, "POIS(%d,%d,%.2e)", size, spatialOrder, penalty); 828 psLogMsg("psModules.imcombine", PS_LOG_INFO, "POIS kernel: %d,%d --> %d elements", 829 size, spatialOrder, num); 815 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(0, PM_SUBTRACTION_KERNEL_POIS, size, NULL, NULL, spatialOrder, penalty, bounds, mode); // Kernels 816 pmSubtractionKernelsMakeDescription(kernels); 817 psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num); 830 818 831 819 if (!p_pmSubtractionKernelsAddGrid(kernels, 0, size)) { … … 871 859 psTrace("psModules.imcombine", 3, "Number of basis functions: %d\n", num); 872 860 873 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM, size, 874 spatialOrder, penalty, bounds, mode); // Kernels 861 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM, size, NULL, NULL, spatialOrder, penalty, bounds, mode); // Kernels 875 862 kernels->inner = inner; 876 psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d,%.2e)", size, inner, binning, spatialOrder, 877 penalty); 878 879 psLogMsg("psModules.imcombine", PS_LOG_INFO, "SPAM kernel: %d,%d,%d,%d --> %d elements", 880 size, inner, binning, spatialOrder, num); 863 kernels->binning = binning; 864 pmSubtractionKernelsMakeDescription(kernels); 865 psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num); 881 866 882 867 kernels->uStop = psVectorAlloc(num, PS_TYPE_S32); … … 970 955 psTrace("psModules.imcombine", 3, "Number of basis functions: %d\n", num); 971 956 972 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES, size, 973 spatialOrder, penalty, bounds, mode); // Kernels 957 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES, size, NULL, NULL, spatialOrder, penalty, bounds, mode); // Kernels 974 958 kernels->inner = inner; 975 psStringAppend(&kernels->description, "FRIES(%d,%d,%d,%.2e)", size, inner, spatialOrder, penalty); 976 977 psLogMsg("psModules.imcombine", PS_LOG_INFO, "FRIES kernel: %d,%d,%d --> %d elements", 978 size, inner, spatialOrder, num); 959 pmSubtractionKernelsMakeDescription(kernels); 960 psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num); 979 961 980 962 kernels->uStop = psVectorAlloc(num, PS_TYPE_S32); … … 1053 1035 PS_ASSERT_INT_LESS_THAN(inner, size, NULL); 1054 1036 1055 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 1056 penalty, bounds, mode); // Kernels 1037 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, penalty, bounds, mode); // Kernels 1057 1038 kernels->type = PM_SUBTRACTION_KERNEL_GUNK; 1058 psStringPrepend(&kernels->description, "GUNK="); 1059 psStringAppend(&kernels->description, "+POIS(%d,%d)", inner, spatialOrder); 1039 kernels->inner = inner; 1040 pmSubtractionKernelsMakeDescription(kernels); 1041 psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, (int) kernels->num); 1060 1042 1061 1043 int numISIS = kernels->num; // Number of ISIS kernels … … 1100 1082 int num = numRings * numPoly; // Total number of basis functions 1101 1083 1102 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS, size, 1103 spatialOrder, penalty, bounds, mode); // Kernels 1084 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS, size, NULL, NULL, spatialOrder, penalty, bounds, mode); // Kernels 1104 1085 kernels->inner = inner; 1105 psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d,%.2e)", size, inner, ringsOrder, spatialOrder, 1106 penalty); 1107 1108 psLogMsg("psModules.imcombine", PS_LOG_INFO, "RINGS kernel: %d,%d,%d,%d --> %d elements", 1109 size, inner, ringsOrder, spatialOrder, num); 1086 kernels->ringsOrder = ringsOrder; 1087 pmSubtractionKernelsMakeDescription(kernels); 1088 psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num); 1110 1089 1111 1090 // Set the Gaussian kernel parameters … … 1405 1384 } 1406 1385 1386 bool pmSubtractionKernelsMakeDescription(pmSubtractionKernels *kernels) { 1387 1388 // free if it exists 1389 psFree (kernels->description); 1390 1391 // generate the description parameter string 1392 psString params = NULL; 1393 if (kernels->fwhms) { 1394 for (int i = 0; i < kernels->fwhms->n; i++) { 1395 psStringAppend(¶ms, "(%.1f,%d)", kernels->fwhms->data.F32[i], kernels->orders->data.S32[i]); 1396 } 1397 } 1398 1399 switch (kernels->type) { 1400 case PM_SUBTRACTION_KERNEL_ISIS: 1401 psStringAppend (&kernels->description, "ISIS(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty); 1402 break; 1403 1404 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 1405 psStringAppend(&kernels->description, "ISIS_RADIAL(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty); 1406 break; 1407 1408 case PM_SUBTRACTION_KERNEL_HERM: 1409 psStringAppend(&kernels->description, "HERM(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty); 1410 break; 1411 1412 case PM_SUBTRACTION_KERNEL_DECONV_HERM: 1413 psStringAppend(&kernels->description, "DECONV_HERM(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty); 1414 break; 1415 1416 case PM_SUBTRACTION_KERNEL_POIS: 1417 psStringAppend(&kernels->description, "POIS(%d,%d,%.2e)", kernels->size, kernels->spatialOrder, kernels->penalty); 1418 break; 1419 1420 case PM_SUBTRACTION_KERNEL_SPAM: 1421 psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d,%.2e)", kernels->size, kernels->inner, kernels->binning, kernels->spatialOrder, kernels->penalty); 1422 break; 1423 1424 case PM_SUBTRACTION_KERNEL_FRIES: 1425 psStringAppend(&kernels->description, "FRIES(%d,%d,%d,%.2e)", kernels->size, kernels->inner, kernels->spatialOrder, kernels->penalty); 1426 break; 1427 1428 // Grid United with Normal Kernel [description: GUNK=ISIS(...)+POIS(...)] 1429 case PM_SUBTRACTION_KERNEL_GUNK: 1430 psStringAppend(&kernels->description, "GUNK=ISIS(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty); 1431 psStringAppend(&kernels->description, "+POIS(%d,%d)", kernels->inner, kernels->spatialOrder); 1432 break; 1433 1434 case PM_SUBTRACTION_KERNEL_RINGS: 1435 psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d,%.2e)", kernels->size, kernels->inner, kernels->ringsOrder, kernels->spatialOrder, kernels->penalty); 1436 break; 1437 1438 default: 1439 psAbort("unknown kernel"); 1440 } 1441 psFree (params); 1442 return true; 1443 } 1444 1407 1445 pmSubtractionKernels *pmSubtractionKernelsCopy(const pmSubtractionKernels *in) 1408 1446 { … … 1435 1473 out->solution1 = in->solution1 ? psVectorCopy(NULL, in->solution1, PS_TYPE_F64) : NULL; 1436 1474 out->solution2 = in->solution2 ? psVectorCopy(NULL, in->solution2, PS_TYPE_F64) : NULL; 1475 out->solution1err = in->solution1err ? psVectorCopy(NULL, in->solution1err, PS_TYPE_F64) : NULL; 1476 out->solution2err = in->solution2err ? psVectorCopy(NULL, in->solution2err, PS_TYPE_F64) : NULL; 1437 1477 out->sampleStamps = psMemIncrRefCounter(in->sampleStamps); 1438 1478 -
trunk/psModules/src/imcombine/pmSubtractionKernels.h
r29601 r30622 2 2 #define PM_SUBTRACTION_KERNELS_H 3 3 4 #include <string.h> 5 #include <pslib.h> 6 7 /// Type of subtraction kernel 8 typedef enum { 9 PM_SUBTRACTION_KERNEL_NONE, ///< Nothing --- an error 10 PM_SUBTRACTION_KERNEL_POIS, ///< Pan-STARRS Optimal Image Subtraction --- delta functions 11 PM_SUBTRACTION_KERNEL_ISIS, ///< Traditional kernel --- gaussians modified by polynomials 12 PM_SUBTRACTION_KERNEL_ISIS_RADIAL, ///< ISIS + higher-order radial Hermitians 13 PM_SUBTRACTION_KERNEL_HERM, ///< Hermitian polynomial kernels 14 PM_SUBTRACTION_KERNEL_DECONV_HERM, ///< Deconvolved Hermitian polynomial kernels 15 PM_SUBTRACTION_KERNEL_SPAM, ///< Summed Pixels for Advanced Matching --- summed delta functions 16 PM_SUBTRACTION_KERNEL_FRIES, ///< Fibonacci Radius Increases Excellence of Subtraction 17 PM_SUBTRACTION_KERNEL_GUNK, ///< Grid United with Normal Kernel --- POIS and ISIS hybrid 18 PM_SUBTRACTION_KERNEL_RINGS, ///< Rings Instead of the Normal Gaussian Subtraction 19 } pmSubtractionKernelsType; 20 21 /// Modes --- specifies which image to convolve 22 typedef enum { 23 PM_SUBTRACTION_MODE_ERR, // Error in the mode 24 PM_SUBTRACTION_MODE_1, // Convolve image 1 25 PM_SUBTRACTION_MODE_2, // Convolve image 2 26 PM_SUBTRACTION_MODE_UNSURE, // Not sure yet which image to convolve so try to satisfy both 27 PM_SUBTRACTION_MODE_DUAL, // Dual convolution 28 } pmSubtractionMode; 29 30 /// Kernels specification 31 typedef struct { 32 pmSubtractionKernelsType type; ///< Type of kernels --- allowing the use of multiple kernels 33 psString description; ///< Description of the kernel parameters 34 int xMin, xMax, yMin, yMax; ///< Bounds of image (for normalisation) 35 long num; ///< Number of kernel components (not including the spatial ones) 36 psVector *u, *v; ///< Offset (for POIS) or polynomial order (for ISIS, HERM or DECONV_HERM) 37 psVector *widths; ///< Gaussian FWHMs (ISIS, HERM or DECONV_HERM) 38 psVector *uStop, *vStop; ///< Width of kernel element (SPAM,FRIES only) 39 psArray *preCalc; ///< Array of images containing pre-calculated kernel (for ISIS, HERM or DECONV_HERM) 40 float penalty; ///< Penalty for wideness 41 psVector *penalties1; ///< Penalty for each kernel component 42 psVector *penalties2; ///< Penalty for each kernel component 43 bool havePenalties; ///< flag to test if we have already calculated the penalties or not. 44 int size; ///< The half-size of the kernel 45 int inner; ///< The size of an inner region 46 int spatialOrder; ///< The spatial order of the kernels 47 int bgOrder; ///< The order for the background fitting 48 pmSubtractionMode mode; ///< Mode for subtraction 49 psVector *solution1, *solution2; ///< Solution for the PSF matching 50 // Quality information 51 float mean, rms; ///< Mean and RMS of chi^2 from stamps 52 int numStamps; ///< Number of good stamps 53 float fResSigmaMean; ///< mean fractional stdev of residuals 54 float fResSigmaStdev; ///< stdev of fractional stdev of residuals 55 float fResOuterMean; ///< mean fractional positive swing in residuals 56 float fResOuterStdev; ///< stdev of fractional positive swing in residuals 57 float fResTotalMean; ///< mean fractional negative swing in residuals 58 float fResTotalStdev; ///< stdev of fractional negative swing in residuals 59 psArray *sampleStamps; ///< array of brightest set of stamps for output visualizations 60 } pmSubtractionKernels; 61 62 // pmSubtractionKernels->preCalc is an array of pmSubtractionKernelPreCalc structures 63 typedef struct { 64 psVector *uCoords; // used by RINGS 65 psVector *vCoords; // used by RINGS 66 psVector *poly; // used by RINGS 67 68 psVector *xKernel; // used by ISIS, HERM, DECONV_HERM 69 psVector *yKernel; // used by ISIS, HERM, DECONV_HERM 70 psKernel *kernel; // used by ISIS, HERM, DECONV_HERM 71 } pmSubtractionKernelPreCalc; 4 // #include <string.h> 5 // #include <pslib.h> 72 6 73 7 // Assertion to check pmSubtractionKernels … … 162 96 pmSubtractionKernelsType type, ///< Kernel type 163 97 int size, ///< Half-size of kernel 98 psVector *fwhms, ///< requested kernel basis function 99 psVector *orders, 164 100 int spatialOrder, ///< Order of spatial variations 165 101 float penalty, ///< Penalty for wideness … … 303 239 ); 304 240 241 bool pmSubtractionKernelsMakeDescription(pmSubtractionKernels *kernels); 242 243 305 244 /// Copy kernels 306 245 /// -
trunk/psModules/src/imcombine/pmSubtractionMask.c
r27402 r30622 7 7 8 8 #include "pmErrorCodes.h" 9 #include "pmFPA.h" 10 #include "pmSubtractionTypes.h" 9 11 #include "pmSubtraction.h" 10 12 #include "pmSubtractionKernels.h" -
trunk/psModules/src/imcombine/pmSubtractionMatch.c
r29596 r30622 11 11 #include "pmFPA.h" 12 12 #include "pmHDUUtils.h" 13 #include "pmSubtractionTypes.h" 14 #include "pmSubtraction.h" 13 15 #include "pmSubtractionParams.h" 14 16 #include "pmSubtractionKernels.h" 15 17 #include "pmSubtractionStamps.h" 16 18 #include "pmSubtractionEquation.h" 17 #include "pmSubtraction.h"18 19 #include "pmSubtractionAnalysis.h" 19 20 #include "pmSubtractionMask.h" … … 27 28 28 29 static bool useFFT = true; // Do convolutions using FFT 29 30 # define SUBMODE PM_SUBTRACTION_EQUATION_ALL31 30 32 31 //#define TESTING … … 59 58 } 60 59 61 62 static bool subtractionGetStamps(pmSubtractionStampList **stamps, // Stamps to read63 const pmReadout *ro1, // Readout 164 const pmReadout *ro2, // Readout 265 const psImage *subMask, // Mask for subtraction, or NULL66 psImage *variance, // Variance map67 const psRegion *region, // Region of interest68 float thresh1, // Threshold for stamp finding on readout 169 float thresh2, // Threshold for stamp finding on readout 270 float stampSpacing, // Spacing between stamps71 float normFrac, // Fraction of flux in window for normalisation window72 float sysError, // Relative systematic error in images73 float skyError, // Relative systematic error in images74 int size, // Kernel half-size75 int footprint, // Convolution footprint for stamps76 pmSubtractionMode mode // Mode for subtraction77 )78 {79 PS_ASSERT_PTR_NON_NULL(stamps, false);80 PM_ASSERT_READOUT_NON_NULL(ro1, false);81 PM_ASSERT_READOUT_NON_NULL(ro2, false);82 PS_ASSERT_IMAGE_NON_NULL(subMask, false);83 PS_ASSERT_IMAGE_NON_NULL(variance, false);84 PS_ASSERT_PTR_NON_NULL(region, false);85 86 psTrace("psModules.imcombine", 3, "Finding stamps...\n");87 88 psImage *image1 = ro1 ? ro1->image : NULL, *image2 = ro2 ? ro2->image : NULL; // Images of interest89 90 *stamps = pmSubtractionStampsFind(*stamps, image1, image2, subMask, region, thresh1, thresh2,91 size, footprint, stampSpacing, normFrac, sysError, skyError, mode);92 if (!*stamps) {93 psError(psErrorCodeLast(), false, "Unable to find stamps.");94 return false;95 }96 97 memCheck(" find stamps");98 99 psTrace("psModules.imcombine", 3, "Extracting stamps...\n");100 if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2->image, variance, size, *region)) {101 psError(psErrorCodeLast(), false, "Unable to extract stamps.");102 return false;103 }104 105 memCheck(" extract stamps");106 pmSubtractionVisualPlotStamps(*stamps, (pmReadout *) ro1);107 return true;108 }109 110 60 // Check input arguments 111 61 static bool subtractionMatchCheck(pmReadout *conv1, pmReadout *conv2, // Convolved images … … 123 73 float badFrac, // Maximum fraction of bad input pixels to accept 124 74 pmSubtractionMode subMode // Mode of subtraction 125 )75 ) 126 76 { 127 77 if (subMode != PM_SUBTRACTION_MODE_2) { … … 473 423 } 474 424 425 bool pmSubtractionMatchAttempt(pmSubtractionQuality **bestMatch, pmSubtractionKernels *kernels, pmSubtractionStampList *stamps, pmSubtractionMode mode, int spatialOrder, bool final) { 426 427 pmSubtractionMode nativeMode = kernels->mode; 428 pmSubtractionMode nativeOrder = kernels->spatialOrder; 429 430 kernels->mode = mode; 431 kernels->spatialOrder = spatialOrder; 432 433 // we always need to recalculate the matrix equation elements... 434 pmSubtractionStampsResetStatus(stamps); 435 436 psTrace("psModules.imcombine", 3, "Convolving stamps as needed...\n"); 437 if (!pmSubtractionConvolveStamps(stamps, kernels)) { 438 psError(psErrorCodeLast(), false, "Unable to convolve stamps."); 439 return false; 440 } 441 442 // step 1: generate the elements of the matrix equation Ax = B 443 psTrace("psModules.imcombine", 3, "Calculating kernel equations...\n"); 444 if (!pmSubtractionCalculateEquation(stamps, kernels)) { 445 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 446 return false; 447 } 448 449 // step 2: solve the matrix equation Ax = B 450 psTrace("psModules.imcombine", 3, "Solving kernel equations...\n"); 451 if (!pmSubtractionSolveEquation(kernels, stamps)) { 452 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 453 return false; 454 } 455 memCheck(" solve equation"); 456 457 // calculate the score for this model fit attempt 458 // XXX store the chisq, flux and moments for stamp rejection 459 pmSubtractionCalculateChisqAndMoments(bestMatch, stamps, kernels); // Stamp deviations 460 461 // display the input and model stamps 462 pmSubtractionVisualShowFit(stamps, kernels); 463 pmSubtractionVisualPlotFit(kernels); 464 pmSubtractionVisualPlotConvKernels(kernels); 465 466 // reset the kernel if desired (on final pass, do not reset) 467 if (!final) { 468 kernels->mode = nativeMode; 469 kernels->spatialOrder = nativeOrder; 470 } else { 471 pmSubtractionKernelsMakeDescription(kernels); 472 psLogMsg("psModules.imcombine", PS_LOG_INFO, "final kernel: %s", kernels->description); 473 } 474 return true; 475 } 475 476 476 477 bool pmSubtractionMatch(pmReadout *conv1, pmReadout *conv2, const pmReadout *ro1, const pmReadout *ro2, … … 478 479 const psArray *sources, const char *stampsName, 479 480 pmSubtractionKernelsType type, int size, int spatialOrder, 480 constpsVector *isisWidths, const psVector *isisOrders,481 psVector *isisWidths, const psVector *isisOrders, 481 482 int inner, int ringsOrder, int binning, float penalty, 482 483 bool optimum, const psVector *optFWHMs, int optOrder, float optThreshold, … … 559 560 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 560 561 562 pmSubtractionQuality *bestMatch = NULL; 563 564 int N_TEST_MODES; 565 int N_TEST_ORDER = spatialOrder; 566 567 pmSubtractionMode TestModes[3]; 568 switch (subMode) { 569 case PM_SUBTRACTION_MODE_1: 570 N_TEST_MODES = 1; 571 TestModes[0] = PM_SUBTRACTION_MODE_1; 572 break; 573 case PM_SUBTRACTION_MODE_2: 574 N_TEST_MODES = 1; 575 TestModes[0] = PM_SUBTRACTION_MODE_2; 576 break; 577 case PM_SUBTRACTION_MODE_DUAL: 578 N_TEST_MODES = 3; 579 TestModes[0] = PM_SUBTRACTION_MODE_1; 580 TestModes[1] = PM_SUBTRACTION_MODE_2; 581 TestModes[2] = PM_SUBTRACTION_MODE_DUAL; 582 break; 583 default: 584 psError(psErrorCodeLast(), false, "For now, only modes 1, 2, and DUAL are supported."); 585 goto MATCH_ERROR; 586 } 587 561 588 memCheck("start"); 562 589 … … 628 655 regionString = psRegionToString(*region); 629 656 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Iso-kernel region: %s out of %d,%d\n", 630 regionString, numCols, numRows);657 regionString, numCols, numRows); 631 658 632 659 if (stampsName && strlen(stampsName) > 0) { … … 640 667 } 641 668 642 // We get the stamps here; we will also attempt to get stamps at the first iteration, but it 643 // doesn't matter. 644 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2, 645 stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) { 646 goto MATCH_ERROR; 647 } 648 649 650 // generate the window function from the set of stamps 651 if (!pmSubtractionStampsGetWindow(stamps, size)) { 652 psError(psErrorCodeLast(), false, "Unable to get stamp window."); 653 goto MATCH_ERROR; 654 } 655 656 // Define kernel basis functions 657 if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) { 658 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, 659 optFWHMs, optOrder, stamps, footprint, 660 optThreshold, penalty, bounds, subMode); 661 if (!kernels) { 662 psErrorClear(); 663 psWarning("Unable to derive optimum ISIS kernel --- switching to default."); 664 } 665 } 666 if (kernels == NULL) { 667 // Not an ISIS/GUNK kernel, or the optimum kernel search failed 668 kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders, 669 inner, binning, ringsOrder, penalty, bounds, subMode); 670 } 671 672 memCheck("kernels"); 673 674 if (subMode == PM_SUBTRACTION_MODE_UNSURE) { 675 pmSubtractionMode newMode = pmSubtractionBestMode(&stamps, &kernels, subMask, rej); 676 switch (newMode) { 677 case PM_SUBTRACTION_MODE_1: 678 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 1 to match image 2."); 679 break; 680 case PM_SUBTRACTION_MODE_2: 681 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 2 to match image 1."); 682 break; 683 default: 684 psError(psErrorCodeLast(), false, "Unable to determine subtraction order."); 685 goto MATCH_ERROR; 686 } 687 subMode = newMode; 688 } 689 690 int numRejected = -1; // Number of rejected stamps in each iteration 691 for (int k = 0; k < iter && numRejected != 0; k++) { 692 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Iteration %d.", k); 693 694 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, 695 stampThresh1, stampThresh2, stampSpacing, normFrac, 696 sysError, skyError, size, footprint, subMode)) { 697 goto MATCH_ERROR; 698 } 699 700 // generate the window function from the set of stamps 701 if (!pmSubtractionStampsGetWindow(stamps, size)) { 702 psError(psErrorCodeLast(), false, "Unable to get stamps window."); 703 goto MATCH_ERROR; 704 } 669 bool tryAgain = true; 670 while (tryAgain) { 671 // We get the stamps here; we will also attempt to get stamps at the first iteration, but it 672 // doesn't matter. 673 if (!pmSubtractionStampsSelect(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2, 674 stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) { 675 goto MATCH_ERROR; 676 } 677 678 // generate the window function from the set of stamps 679 if (!pmSubtractionStampsGetWindow(&tryAgain, stamps, size)) { 680 // if we failed, it might be due to the desired normWindow being larger than the current footprint. 681 // in this case, just adjust the footprint and try again. 682 if (tryAgain) { 683 // keep the border constant 684 int border = footprint - size; 685 size = PS_MAX(stamps->normWindow1, stamps->normWindow2) + 2; 686 footprint = size + border; 687 688 // we need to reconstruct everything, so just free the stamps here and retry 689 psFree(stamps); 690 } else { 691 // unrecoverable error 692 psError(psErrorCodeLast(), false, "Unable to get stamp window."); 693 goto MATCH_ERROR; 694 } 695 } 696 } 697 698 // check on the kernel scaling -- if the kron-based radial moments are very different, adjust to match them 699 { 700 // float fwhm1; 701 // float fwhm2; 702 // pmSubtractionGetFWHMs(&fwhm1, &fwhm2); 703 // psAssert(isfinite(fwhm1), "fwhm 1 not set"); 704 // psAssert(isfinite(fwhm2), "fwhm 2 not set"); 705 706 // XXX this is BAD: depends on the relationship below: 707 // stamps->normWindow1 = 2.75*R1; 708 // stamps->normWindow2 = 2.75*R2; 709 float radMoment1 = stamps->normWindow1 / 2.75; 710 float radMoment2 = stamps->normWindow2 / 2.75; 711 pmSubtractionParamsScale(NULL, NULL, isisWidths, radMoment1, radMoment2); 712 713 // float maxFWHM = PS_MAX(fwhm1, fwhm2); 714 // float maxRadial = PS_MAX(radMoment1, radMoment2); 715 716 // if (fabs(2.0*(maxFWHM - maxRadial)/(maxFWHM + maxRadial)) > 0.25) { 717 // if (1) { 718 // 719 // float scale = maxRadial / maxFWHM; 720 // psLogMsg ("psModules.imcombine", PS_LOG_INFO, "Kron and FWHM scales are quite different, re-scale by %f to use Kron", scale); 721 // 722 // for (int i = 0; i < isisWidths->n; i++) { 723 // isisWidths->data.F32[i] *= scale; 724 // } 725 // } 726 } 727 728 // Define kernel basis functions 729 if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) { 730 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, 731 optFWHMs, optOrder, stamps, footprint, 732 optThreshold, penalty, bounds, subMode); 733 if (!kernels) { 734 psErrorClear(); 735 psWarning("Unable to derive optimum ISIS kernel --- switching to default."); 736 } 737 } 738 if (kernels == NULL) { 739 // Not an ISIS/GUNK kernel, or the optimum kernel search failed 740 kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders, 741 inner, binning, ringsOrder, penalty, bounds, subMode); 742 } 743 744 memCheck("kernels"); 745 746 if (subMode == PM_SUBTRACTION_MODE_UNSURE) { 747 pmSubtractionMode newMode = pmSubtractionBestMode(&stamps, &kernels, subMask, rej); 748 switch (newMode) { 749 case PM_SUBTRACTION_MODE_1: 750 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 1 to match image 2."); 751 break; 752 case PM_SUBTRACTION_MODE_2: 753 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 2 to match image 1."); 754 break; 755 default: 756 psError(psErrorCodeLast(), false, "Unable to determine subtraction order."); 757 goto MATCH_ERROR; 758 } 759 subMode = newMode; 760 } 761 762 int numRejected = -1; // Number of rejected stamps in each iteration 763 for (int k = 0; (k < iter) && (numRejected != 0); k++) { 764 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Iteration %d.", k); 765 766 bool tryAgain = true; 767 while (tryAgain) { 768 // We get the stamps here; we will also attempt to get stamps at the first iteration, but it 769 // doesn't matter. 770 if (!pmSubtractionStampsSelect(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2, 771 stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) { 772 goto MATCH_ERROR; 773 } 774 775 // generate the window function from the set of stamps 776 if (!pmSubtractionStampsGetWindow(&tryAgain, stamps, size)) { 777 // if we failed, it might be due to the desired normWindow being larger than the current footprint. 778 // in this case, just adjust the footprint and try again. 779 if (tryAgain) { 780 footprint = PS_MAX(stamps->normWindow1, stamps->normWindow2) + 2; 781 782 // we need to reconstruct everything, so just free the stamps here and retry 783 psFree(stamps); 784 } else { 785 // unrecoverable error 786 psError(psErrorCodeLast(), false, "Unable to get stamp window."); 787 goto MATCH_ERROR; 788 } 789 } 790 } 705 791 706 792 // step 0 : calculate the normalizations, pass along to the next steps via stamps->normValue 707 psTrace("psModules.imcombine", 3, "Calculating normalization...\n"); 708 if (!pmSubtractionCalculateNormalization(stamps, kernels->mode)) { 709 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 710 goto MATCH_ERROR; 711 } 712 713 // step 0b : calculate the moments, pass along to the next steps via stamps->normValue 714 // XXX this step is now skipped -- delete 715 psTrace("psModules.imcombine", 3, "Calculating normalization...\n"); 716 if (!pmSubtractionCalculateMoments(kernels, stamps)) { 717 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 718 goto MATCH_ERROR; 719 } 720 721 // step 1: generate the elements of the matrix equation Ax = B 722 psTrace("psModules.imcombine", 3, "Calculating kernel equations...\n"); 723 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 724 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 725 goto MATCH_ERROR; 726 } 727 728 // step 2: solve the matrix equation Ax = B 729 psTrace("psModules.imcombine", 3, "Solving kernel equations...\n"); 730 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 731 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 732 goto MATCH_ERROR; 733 } 734 memCheck(" solve equation"); 735 736 pmSubtractionVisualPlotConvKernels(kernels); 737 738 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 739 if (!deviations) { 740 psError(psErrorCodeLast(), false, "Unable to calculate deviations."); 741 goto MATCH_ERROR; 742 } 743 memCheck(" calculate deviations"); 744 745 psTrace("psModules.imcombine", 3, "Rejecting stamps...\n"); 746 numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej); 747 if (numRejected < 0) { 748 psError(psErrorCodeLast(), false, "Unable to reject stamps."); 749 psFree(deviations); 750 goto MATCH_ERROR; 751 } 752 psFree(deviations); 753 754 memCheck(" reject stamps"); 755 } 756 757 // if we hit the max number of iterations and we have rejected stamps, re-solve 758 if (numRejected > 0) { 759 760 // step 1: generate the elements of the matrix equation Ax = B 761 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 762 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 763 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 764 goto MATCH_ERROR; 765 } 766 767 // step 2: solve the matrix equation Ax = B 768 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 769 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 770 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 771 goto MATCH_ERROR; 772 } 773 774 pmSubtractionVisualPlotConvKernels(kernels); 775 776 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 777 if (!deviations) { 778 psError(psErrorCodeLast(), false, "Unable to calculate deviations."); 779 goto MATCH_ERROR; 780 } 781 pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN); 782 psFree(deviations); 783 } 784 psFree(stamps); 785 stamps = NULL; 786 787 memCheck("solution"); 788 789 if (!pmSubtractionAnalysis(analysis, header, kernels, region, numCols, numRows)) { 790 psError(psErrorCodeLast(), false, "Unable to generate QA data"); 791 goto MATCH_ERROR; 792 } 793 memCheck("diag outputs"); 794 795 psTrace("psModules.imcombine", 2, "Convolving...\n"); 796 if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac, 797 kernelError, covarFrac, region, kernels, true, useFFT)) { 798 psError(psErrorCodeLast(), false, "Unable to convolve image."); 799 goto MATCH_ERROR; 800 } 801 802 psFree(kernels); 803 kernels = NULL; 804 } 793 psTrace("psModules.imcombine", 3, "Calculating normalization...\n"); 794 if (!pmSubtractionCalculateNormalization(stamps, kernels->mode)) { 795 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 796 goto MATCH_ERROR; 797 } 798 799 // on each iteration, we start from scratch 800 psFree(bestMatch); 801 802 // choose the spatial order and subtraction direction (1, 2, dual) 803 // XXX need to make these respect recipe somewhat 804 for (int order = 0; order <= N_TEST_ORDER; order++) { 805 for (int j = 0; j < N_TEST_MODES; j++) { 806 if (!pmSubtractionMatchAttempt(&bestMatch, kernels, stamps, TestModes[j], order, false)) { 807 goto MATCH_ERROR; 808 } 809 } 810 } 811 812 // reject the deviant stamps based on the stats of the best match 813 psTrace("psModules.imcombine", 3, "Rejecting stamps...\n"); 814 numRejected = pmSubtractionRejectStamps(kernels, stamps, bestMatch, subMask, rej); 815 if (numRejected < 0) { 816 psError(psErrorCodeLast(), false, "Unable to reject stamps."); 817 goto MATCH_ERROR; 818 } 819 memCheck(" reject stamps"); 820 } 821 822 // apply the best fit so we are ready to roll 823 psLogMsg("psModules.imcombine", PS_LOG_INFO, "applying order: %d, mode: %d\n", bestMatch->spatialOrder, bestMatch->mode); 824 if (!pmSubtractionMatchAttempt(NULL, kernels, stamps, bestMatch->mode, bestMatch->spatialOrder, true)) { 825 goto MATCH_ERROR; 826 } 827 psFree(stamps); 828 psFree(bestMatch); 829 memCheck("solution"); 830 831 if (!pmSubtractionAnalysis(analysis, header, kernels, region, numCols, numRows)) { 832 psError(psErrorCodeLast(), false, "Unable to generate QA data"); 833 goto MATCH_ERROR; 834 } 835 memCheck("diag outputs"); 836 837 psTrace("psModules.imcombine", 2, "Convolving...\n"); 838 if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac, 839 kernelError, covarFrac, region, kernels, true, useFFT)) { 840 psError(psErrorCodeLast(), false, "Unable to convolve image."); 841 goto MATCH_ERROR; 842 } 843 844 psFree(kernels); 845 kernels = NULL; 846 } 805 847 } 806 848 psFree(rng); … … 816 858 817 859 if (conv1 && !pmSubtractionBorder(conv1->image, conv1->variance, conv1->mask, size, maskBad)) { 818 psError(psErrorCodeLast(), false, "Unable to set border of convolved image.");819 goto MATCH_ERROR;860 psError(psErrorCodeLast(), false, "Unable to set border of convolved image."); 861 goto MATCH_ERROR; 820 862 } 821 863 if (conv2 && !pmSubtractionBorder(conv2->image, conv2->variance, conv2->mask, size, maskBad)) { 822 psError(psErrorCodeLast(), false, "Unable to set border of convolved image.");823 goto MATCH_ERROR;864 psError(psErrorCodeLast(), false, "Unable to set border of convolved image."); 865 goto MATCH_ERROR; 824 866 } 825 867 … … 832 874 #ifdef TESTING 833 875 { 834 if (subMode == PM_SUBTRACTION_MODE_1 || subMode == PM_SUBTRACTION_MODE_DUAL) {835 psFits *fits = psFitsOpen("convolved1.fits", "w");836 psFitsWriteImage(fits, NULL, conv1->image, 0, NULL);837 psFitsClose(fits);838 }839 840 if (subMode == PM_SUBTRACTION_MODE_2 || subMode == PM_SUBTRACTION_MODE_DUAL) {841 psFits *fits = psFitsOpen("convolved2.fits", "w");842 psFitsWriteImage(fits, NULL, conv2->image, 0, NULL);843 psFitsClose(fits);844 }876 if (subMode == PM_SUBTRACTION_MODE_1 || subMode == PM_SUBTRACTION_MODE_DUAL) { 877 psFits *fits = psFitsOpen("convolved1.fits", "w"); 878 psFitsWriteImage(fits, NULL, conv1->image, 0, NULL); 879 psFitsClose(fits); 880 } 881 882 if (subMode == PM_SUBTRACTION_MODE_2 || subMode == PM_SUBTRACTION_MODE_DUAL) { 883 psFits *fits = psFitsOpen("convolved2.fits", "w"); 884 psFitsWriteImage(fits, NULL, conv2->image, 0, NULL); 885 psFitsClose(fits); 886 } 845 887 } 846 888 #endif … … 858 900 psFree(variance); 859 901 psFree(rng); 902 psFree(bestMatch); 860 903 return false; 861 904 } … … 866 909 // increment). 867 910 static int subtractionOrderWidth(const psKernel *kernel, // Image 868 float bg, // Background in image869 int size, // Maximum size870 const psArray *models, // Buffer of models871 const psVector *modelSums // Buffer of model sums911 float bg, // Background in image 912 int size, // Maximum size 913 const psArray *models, // Buffer of models 914 const psVector *modelSums // Buffer of model sums 872 915 ) 873 916 { … … 882 925 psVector *chi2 = psVectorAlloc(size, PS_TYPE_F32); // chi^2 as a function of radius 883 926 for (int sigma = 0; sigma < size; sigma++) { 884 double sumFG = 0.0; // Sum for calculating the normalisation of the Gaussian885 psKernel *model = models->data[sigma]; // Model of interest886 for (int y = yMin; y <= yMax; y++) {887 for (int x = xMin; x <= xMax; x++) {888 sumFG += model->kernel[y][x] * (kernel->kernel[y][x] - bg);889 }890 }891 float norm = sumFG * modelSums->data.F64[sigma]; // Normalisation for Gaussian892 double sumDev2 = 0.0; // Sum of square deviations893 for (int y = yMin; y <= yMax; y++) {894 for (int x = xMin; x <= xMax; x++) {895 float dev = kernel->kernel[y][x] - bg - norm * model->kernel[y][x]; // Deviation896 sumDev2 += PS_SQR(dev);897 }898 }899 chi2->data.F32[sigma] = sumDev2;927 double sumFG = 0.0; // Sum for calculating the normalisation of the Gaussian 928 psKernel *model = models->data[sigma]; // Model of interest 929 for (int y = yMin; y <= yMax; y++) { 930 for (int x = xMin; x <= xMax; x++) { 931 sumFG += model->kernel[y][x] * (kernel->kernel[y][x] - bg); 932 } 933 } 934 float norm = sumFG * modelSums->data.F64[sigma]; // Normalisation for Gaussian 935 double sumDev2 = 0.0; // Sum of square deviations 936 for (int y = yMin; y <= yMax; y++) { 937 for (int x = xMin; x <= xMax; x++) { 938 float dev = kernel->kernel[y][x] - bg - norm * model->kernel[y][x]; // Deviation 939 sumDev2 += PS_SQR(dev); 940 } 941 } 942 chi2->data.F32[sigma] = sumDev2; 900 943 } 901 944 … … 904 947 float bestChi2 = INFINITY; // Best chi^2 905 948 for (int i = 0; i < size; i++) { 906 if (chi2->data.F32[i] < bestChi2) {907 bestChi2 = chi2->data.F32[i];908 bestIndex = i;909 }949 if (chi2->data.F32[i] < bestChi2) { 950 bestChi2 = chi2->data.F32[i]; 951 bestIndex = i; 952 } 910 953 } 911 954 psFree(chi2); … … 916 959 917 960 bool pmSubtractionOrderStamp(psVector *ratios, psVector *mask, const pmSubtractionStampList *stamps, 918 const psArray *models, const psVector *modelSums,919 int index, float bg1, float bg2)961 const psArray *models, const psVector *modelSums, 962 int index, float bg1, float bg2) 920 963 { 921 964 PS_ASSERT_VECTOR_NON_NULL(ratios, false); … … 931 974 pmSubtractionStamp *stamp = stamps->stamps->data[index]; // Stamp of interest 932 975 psAssert(stamp->status == PM_SUBTRACTION_STAMP_CALCULATE || stamp->status == PM_SUBTRACTION_STAMP_USED, 933 "We checked this earlier.");976 "We checked this earlier."); 934 977 935 978 // Widths of stars … … 938 981 939 982 if (width1 == 0 || width2 == 0) { 940 ratios->data.F32[index] = NAN;941 mask->data.PS_TYPE_VECTOR_MASK_DATA[index] = 0xff;983 ratios->data.F32[index] = NAN; 984 mask->data.PS_TYPE_VECTOR_MASK_DATA[index] = 0xff; 942 985 } else { 943 ratios->data.F32[index] = (float)width1 / (float)width2;944 mask->data.PS_TYPE_VECTOR_MASK_DATA[index] = 0;945 psTrace("psModules.imcombine", 3, "Stamp %d (%.1f,%.1f) widths: %d, %d --> %f\n",946 index, stamp->x, stamp->y, width1, width2, ratios->data.F32[index]);986 ratios->data.F32[index] = (float)width1 / (float)width2; 987 mask->data.PS_TYPE_VECTOR_MASK_DATA[index] = 0; 988 psTrace("psModules.imcombine", 3, "Stamp %d (%.1f,%.1f) widths: %d, %d --> %f\n", 989 index, stamp->x, stamp->y, width1, width2, ratios->data.F32[index]); 947 990 } 948 991 … … 978 1021 psVector *modelSums = psVectorAlloc(size, PS_TYPE_F64); // Gaussian model sums 979 1022 for (int sigma = 0; sigma < size; sigma++) { 980 psKernel *model = psKernelAlloc(-size, size, -size, size); // Gaussian model981 float invSigma2 = 1.0 / (float)PS_SQR(1 + sigma); // Inverse sigma squared982 double sumGG = 0.0; // Sum of square of Gaussian983 for (int y = -size; y <= size; y++) {984 int y2 = PS_SQR(y); // y squared985 for (int x = -size; x <= size; x++) {986 float rad2 = PS_SQR(x) + y2; // Radius squared987 float value = expf(-rad2 * invSigma2); // Model value988 model->kernel[y][x] = value;989 sumGG += PS_SQR(value);990 }991 }992 models->data[sigma] = model;993 modelSums->data.F64[sigma] = 1.0 / sumGG;1023 psKernel *model = psKernelAlloc(-size, size, -size, size); // Gaussian model 1024 float invSigma2 = 1.0 / (float)PS_SQR(1 + sigma); // Inverse sigma squared 1025 double sumGG = 0.0; // Sum of square of Gaussian 1026 for (int y = -size; y <= size; y++) { 1027 int y2 = PS_SQR(y); // y squared 1028 for (int x = -size; x <= size; x++) { 1029 float rad2 = PS_SQR(x) + y2; // Radius squared 1030 float value = expf(-rad2 * invSigma2); // Model value 1031 model->kernel[y][x] = value; 1032 sumGG += PS_SQR(value); 1033 } 1034 } 1035 models->data[sigma] = model; 1036 modelSums->data.F64[sigma] = 1.0 / sumGG; 994 1037 } 995 1038 996 1039 // Fit models to stamps 997 1040 for (int i = 0; i < stamps->num; i++) { 998 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest999 if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE && stamp->status != PM_SUBTRACTION_STAMP_USED) {1000 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff;1001 continue;1002 }1003 1004 if (pmSubtractionThreaded()) {1005 psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_ORDER");1006 psArrayAdd(job->args, 1, ratios);1007 psArrayAdd(job->args, 1, mask);1008 psArrayAdd(job->args, 1, stamps);1009 psArrayAdd(job->args, 1, models);1010 psArrayAdd(job->args, 1, modelSums);1011 PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32);1012 PS_ARRAY_ADD_SCALAR(job->args, bg1, PS_TYPE_F32);1013 PS_ARRAY_ADD_SCALAR(job->args, bg2, PS_TYPE_F32);1014 if (!psThreadJobAddPending(job)) {1015 return false;1016 }1017 } else {1018 if (!pmSubtractionOrderStamp(ratios, mask, stamps, models, modelSums, i, bg1, bg2)) {1019 psError(psErrorCodeLast(), false, "Unable to measure PSF width for stamp %d", i);1020 psFree(models);1021 psFree(modelSums);1022 psFree(ratios);1023 psFree(mask);1024 return false;1025 }1026 }1041 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 1042 if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE && stamp->status != PM_SUBTRACTION_STAMP_USED) { 1043 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff; 1044 continue; 1045 } 1046 1047 if (pmSubtractionThreaded()) { 1048 psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_ORDER"); 1049 psArrayAdd(job->args, 1, ratios); 1050 psArrayAdd(job->args, 1, mask); 1051 psArrayAdd(job->args, 1, stamps); 1052 psArrayAdd(job->args, 1, models); 1053 psArrayAdd(job->args, 1, modelSums); 1054 PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32); 1055 PS_ARRAY_ADD_SCALAR(job->args, bg1, PS_TYPE_F32); 1056 PS_ARRAY_ADD_SCALAR(job->args, bg2, PS_TYPE_F32); 1057 if (!psThreadJobAddPending(job)) { 1058 return false; 1059 } 1060 } else { 1061 if (!pmSubtractionOrderStamp(ratios, mask, stamps, models, modelSums, i, bg1, bg2)) { 1062 psError(psErrorCodeLast(), false, "Unable to measure PSF width for stamp %d", i); 1063 psFree(models); 1064 psFree(modelSums); 1065 psFree(ratios); 1066 psFree(mask); 1067 return false; 1068 } 1069 } 1027 1070 } 1028 1071 1029 1072 if (!psThreadPoolWait(true)) { 1030 psError(psErrorCodeLast(), false, "Error waiting for threads.");1031 psFree(models);1032 psFree(modelSums);1033 psFree(ratios);1034 psFree(mask);1035 return false;1073 psError(psErrorCodeLast(), false, "Error waiting for threads."); 1074 psFree(models); 1075 psFree(modelSums); 1076 psFree(ratios); 1077 psFree(mask); 1078 return false; 1036 1079 } 1037 1080 … … 1041 1084 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); 1042 1085 if (!psVectorStats(stats, ratios, NULL, mask, 0xff)) { 1043 psError(psErrorCodeLast(), false, "Unable to calculate statistics for moments ratio.");1044 psFree(mask);1045 psFree(ratios);1046 psFree(stats);1047 return PM_SUBTRACTION_MODE_ERR;1086 psError(psErrorCodeLast(), false, "Unable to calculate statistics for moments ratio."); 1087 psFree(mask); 1088 psFree(ratios); 1089 psFree(stats); 1090 return PM_SUBTRACTION_MODE_ERR; 1048 1091 } 1049 1092 psFree(ratios); … … 1052 1095 // XXX raise an error here or not? 1053 1096 if (isnan(stats->robustMedian)) { 1054 psFree(stats);1055 return PM_SUBTRACTION_MODE_ERR;1097 psFree(stats); 1098 return PM_SUBTRACTION_MODE_ERR; 1056 1099 } 1057 1100 … … 1066 1109 // Test a subtraction mode by performing a single iteration 1067 1110 static bool subtractionModeTest(pmSubtractionStampList *stamps, // Stamps to use to find best mode 1068 pmSubtractionKernels *kernels, // Kernel description1069 const char *description, // Description for trace1070 psImage *subMask, // Subtraction mask1071 float rej // Rejection threshold1072 )1111 pmSubtractionKernels *kernels, // Kernel description 1112 const char *description, // Description for trace 1113 psImage *subMask, // Subtraction mask 1114 float rej // Rejection threshold 1115 ) 1073 1116 { 1074 1117 assert(stamps); 1075 1118 assert(kernels); 1076 1119 1120 psAbort("this function is not working"); 1121 # if (0) 1122 psTrace("psModules.imcombine", 3, "Convolving stamps as needed...\n"); 1123 if (!pmSubtractionConvolveStamps(stamps, kernels)) { 1124 psError(psErrorCodeLast(), false, "Unable to convolve stamps."); 1125 return false; 1126 } 1127 1077 1128 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1078 if (!pmSubtractionCalculateEquation(stamps, kernels , SUBMODE)) {1079 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");1080 return false;1129 if (!pmSubtractionCalculateEquation(stamps, kernels)) { 1130 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1131 return false; 1081 1132 } 1082 1133 1083 1134 psTrace("psModules.imcombine", 3, "Solving %s normalization equation...\n", description); 1084 if (!pmSubtractionSolveEquation(kernels, stamps , SUBMODE)) {1085 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");1086 return false;1135 if (!pmSubtractionSolveEquation(kernels, stamps)) { 1136 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1137 return false; 1087 1138 } 1088 1139 … … 1090 1141 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 1091 1142 if (!deviations) { 1092 psError(psErrorCodeLast(), false, "Unable to calculate deviations."); 1093 return false; 1094 } 1095 1143 psError(psErrorCodeLast(), false, "Unable to calculate deviations."); 1144 return false; 1145 } 1146 1147 // XXX this needs to be made consistent with the modified 'reject stamps' function 1096 1148 psTrace("psModules.imcombine", 3, "Rejecting %s stamps...\n", description); 1097 1149 long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej); 1098 1150 if (numRejected < 0) { 1099 psError(psErrorCodeLast(), false, "Unable to reject stamps.");1100 psFree(deviations);1101 return false;1151 psError(psErrorCodeLast(), false, "Unable to reject stamps."); 1152 psFree(deviations); 1153 return false; 1102 1154 } 1103 1155 psFree(deviations); 1104 1156 1105 1157 if (numRejected > 0) { 1106 // Allow re-fit with reduced stamps set1107 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description);1108 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_ALL)) {1109 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");1110 return false;1111 }1112 1113 psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description);1114 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_ALL)) {1115 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");1116 return false;1117 }1118 psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description);1119 1120 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations1121 if (!deviations) {1122 psError(psErrorCodeLast(), false, "Unable to calculate deviations.");1123 return false;1124 }1125 psTrace("psModules.imcombine", 3, "Measuring %s quality...\n", description);1126 long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN);1127 if (numRejected < 0) {1128 psError(psErrorCodeLast(), false, "Unable to reject stamps.");1129 psFree(deviations);1130 return false;1131 }1132 psFree(deviations);1133 } 1134 1158 // Allow re-fit with reduced stamps set 1159 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1160 if (!pmSubtractionCalculateEquation(stamps, kernels)) { 1161 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1162 return false; 1163 } 1164 1165 psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description); 1166 if (!pmSubtractionSolveEquation(kernels, stamps)) { 1167 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1168 return false; 1169 } 1170 psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description); 1171 1172 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 1173 if (!deviations) { 1174 psError(psErrorCodeLast(), false, "Unable to calculate deviations."); 1175 return false; 1176 } 1177 psTrace("psModules.imcombine", 3, "Measuring %s quality...\n", description); 1178 long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN); 1179 if (numRejected < 0) { 1180 psError(psErrorCodeLast(), false, "Unable to reject stamps."); 1181 psFree(deviations); 1182 return false; 1183 } 1184 psFree(deviations); 1185 } 1186 # endif 1135 1187 return true; 1136 1188 } … … 1138 1190 1139 1191 pmSubtractionMode pmSubtractionBestMode(pmSubtractionStampList **stamps, pmSubtractionKernels **kernels, 1140 const psImage *subMask, float rej)1192 const psImage *subMask, float rej) 1141 1193 { 1142 1194 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(*stamps, PM_SUBTRACTION_MODE_ERR); … … 1150 1202 1151 1203 if (!subtractionModeTest(stamps1, kernels1, "convolve 1", subMask1, rej)) { 1152 psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 1");1153 psFree(stamps1);1154 psFree(kernels1);1155 psFree(subMask1);1156 return PM_SUBTRACTION_MODE_ERR;1204 psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 1"); 1205 psFree(stamps1); 1206 psFree(kernels1); 1207 psFree(subMask1); 1208 return PM_SUBTRACTION_MODE_ERR; 1157 1209 } 1158 1210 psFree(subMask1); … … 1165 1217 1166 1218 if (!subtractionModeTest(stamps2, kernels2, "convolve 2", subMask2, rej)) { 1167 psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 2");1168 psFree(stamps2);1169 psFree(kernels2);1170 psFree(subMask2);1171 psFree(stamps1);1172 psFree(kernels1);1173 return PM_SUBTRACTION_MODE_ERR;1219 psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 2"); 1220 psFree(stamps2); 1221 psFree(kernels2); 1222 psFree(subMask2); 1223 psFree(stamps1); 1224 psFree(kernels1); 1225 return PM_SUBTRACTION_MODE_ERR; 1174 1226 } 1175 1227 psFree(subMask2); … … 1179 1231 pmSubtractionKernels *bestKernels = NULL; // Best choice for kernels 1180 1232 psLogMsg("psModules.imcombine", PS_LOG_INFO, 1181 "Image 1: %f +/- %f from %d stamps\nImage 2: %f +/- %f from %d stamps\n",1182 kernels1->mean, kernels1->rms, kernels1->numStamps,1183 kernels2->mean, kernels2->rms, kernels2->numStamps);1233 "Image 1: %f +/- %f from %d stamps\nImage 2: %f +/- %f from %d stamps\n", 1234 kernels1->mean, kernels1->rms, kernels1->numStamps, 1235 kernels2->mean, kernels2->rms, kernels2->numStamps); 1184 1236 1185 1237 if (kernels1->mean < kernels2->mean) { 1186 bestStamps = stamps1;1187 bestKernels = kernels1;1238 bestStamps = stamps1; 1239 bestKernels = kernels1; 1188 1240 } else { 1189 bestStamps = stamps2;1190 bestKernels = kernels2;1241 bestStamps = stamps2; 1242 bestKernels = kernels2; 1191 1243 } 1192 1244 … … 1204 1256 } 1205 1257 1206 1207 bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths, 1208 float scaleRef, float scaleMin, float scaleMax) 1258 static float scaleRefOption = NAN; 1259 static float scaleMinOption = NAN; 1260 static float scaleMaxOption = NAN; 1261 static bool scaleOption = false; 1262 1263 bool pmSubtractionParamScaleOptions(bool scale, float scaleRef, float scaleMin, float scaleMax) { 1264 1265 if (scale) { 1266 PS_ASSERT_FLOAT_LARGER_THAN(scaleRef, 0.0, false); 1267 PS_ASSERT_FLOAT_LARGER_THAN(scaleMin, 0.0, false); 1268 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, 0.0, false); 1269 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, scaleMin, false); 1270 } 1271 1272 scaleRefOption = scaleRef; 1273 scaleMinOption = scaleMin; 1274 scaleMaxOption = scaleMax; 1275 scaleOption = scale; 1276 1277 return true; 1278 } 1279 1280 bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths, float fwhm1, float fwhm2) 1209 1281 { 1210 PS_ASSERT_PTR_NON_NULL(kernelSize, false);1211 PS_ASSERT_PTR_NON_NULL(stampSize, false);1282 // PS_ASSERT_PTR_NON_NULL(kernelSize, false); 1283 // PS_ASSERT_PTR_NON_NULL(stampSize, false); 1212 1284 PS_ASSERT_VECTOR_NON_NULL(widths, false); 1213 1285 PS_ASSERT_VECTOR_TYPE(widths, PS_TYPE_F32, false); 1214 PS_ASSERT_FLOAT_LARGER_THAN(scaleRef, 0.0, false); 1215 PS_ASSERT_FLOAT_LARGER_THAN(scaleMin, 0.0, false); 1216 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, 0.0, false); 1217 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, scaleMin, false); 1218 1219 float fwhm1; 1220 float fwhm2; 1221 1222 pmSubtractionGetFWHMs(&fwhm1, &fwhm2); 1223 psAssert(isfinite(fwhm1), "fwhm 1 not set"); 1224 psAssert(isfinite(fwhm2), "fwhm 2 not set"); 1286 1287 if (!scaleOption) return true; 1288 1289 // pmSubtractionGetFWHMs(&fwhm1, &fwhm2); 1290 // psAssert(isfinite(fwhm1), "fwhm 1 not set"); 1291 // psAssert(isfinite(fwhm2), "fwhm 2 not set"); 1225 1292 1226 1293 // float diff = sqrtf(PS_SQR(PS_MAX(fwhm1, fwhm2)) - PS_SQR(PS_MIN(fwhm1, fwhm2))); // Difference 1227 float scale = PS_MAX(fwhm1, fwhm2) / scaleRef ; // Scaling factor1228 1229 if (isfinite(scaleMin ) && scale < scaleMin) {1230 scale = scaleMin;1231 } 1232 if (isfinite(scaleMax ) && scale > scaleMax) {1233 scale = scaleMax;1294 float scale = PS_MAX(fwhm1, fwhm2) / scaleRefOption; // Scaling factor 1295 1296 if (isfinite(scaleMinOption) && scale < scaleMinOption) { 1297 scale = scaleMinOption; 1298 } 1299 if (isfinite(scaleMaxOption) && scale > scaleMaxOption) { 1300 scale = scaleMaxOption; 1234 1301 } 1235 1302 1236 1303 for (int i = 0; i < widths->n; i++) { 1237 widths->data.F32[i] *= scale; 1238 } 1239 *kernelSize = *kernelSize * scale + 0.5; 1240 *stampSize = *stampSize * scale + 0.5; 1241 1242 psLogMsg("psModules.imcombine", PS_LOG_INFO, 1243 "Scaling kernel parameters by %f: %d %d", scale, *kernelSize, *stampSize); 1304 widths->data.F32[i] *= scale; 1305 } 1306 if (kernelSize) { 1307 *kernelSize = *kernelSize * scale + 0.5; 1308 } 1309 if (stampSize) { 1310 *stampSize = *stampSize * scale + 0.5; 1311 } 1312 1313 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Scaling kernel parameters by %f", scale); 1314 if (kernelSize) psLogMsg("psModules.imcombine", PS_LOG_INFO, " modified kernel size %d", *kernelSize); 1315 if (stampSize) psLogMsg("psModules.imcombine", PS_LOG_INFO, " modified stamp size %d", *stampSize); 1244 1316 1245 1317 return true; -
trunk/psModules/src/imcombine/pmSubtractionMatch.h
r29543 r30622 8 8 #include <pmSubtractionKernels.h> 9 9 #include <pmSubtractionStamps.h> 10 #include <pmSubtraction.h> 10 11 11 12 /// Match two images … … 26 27 int size, ///< Kernel half-size 27 28 int order, ///< Spatial polynomial order 28 constpsVector *widths, ///< ISIS Gaussian widths29 psVector *widths, ///< ISIS Gaussian widths 29 30 const psVector *orders, ///< ISIS Polynomial orders 30 31 int inner, ///< Inner radius for various kernel types … … 100 101 101 102 /// Scale subtraction parameters according to the FWHMs of the inputs 102 bool pmSubtractionParamsScale( 103 int *kernelSize, ///< Half-size of the kernel 104 int *stampSize, ///< Half-size of the stamp (footprint) 105 psVector *widths, ///< ISIS widths 106 float scaleRef, ///< Reference width for scaling 107 float scaleMin, ///< Minimum scaling ratio, or NAN 108 float scaleMax ///< Maximum scaling ratio, or NAN 103 // bool pmSubtractionParamsScale( 104 // int *kernelSize, ///< Half-size of the kernel 105 // int *stampSize, ///< Half-size of the stamp (footprint) 106 // psVector *widths, ///< ISIS widths 107 // float scaleRef, ///< Reference width for scaling 108 // float scaleMin, ///< Minimum scaling ratio, or NAN 109 // float scaleMax ///< Maximum scaling ratio, or NAN 110 // ); 111 112 bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths, float fwhm1, float fwhm2); 113 114 bool pmSubtractionParamScaleOptions(bool scale, float scaleRef, float scaleMin, float scaleMax); 115 116 bool pmSubtractionMatchAttempt( 117 pmSubtractionQuality **bestMatch, 118 pmSubtractionKernels *kernels, 119 pmSubtractionStampList *stamps, 120 pmSubtractionMode mode, 121 int spatialOrder, 122 bool final 109 123 ); 110 124 -
trunk/psModules/src/imcombine/pmSubtractionParams.c
r27086 r30622 9 9 10 10 #include "pmErrorCodes.h" 11 #include "pmFPA.h" 12 #include "pmSubtractionTypes.h" 13 #include "pmSubtraction.h" 11 14 #include "pmSubtractionStamps.h" 12 #include "pmSubtraction.h"13 15 #include "pmSubtractionParams.h" 14 16 … … 16 18 17 19 #if 0 20 // XXX this was moved to pmSubtraction.c in r15443 -- delete 18 21 // Convolve the reference stamp by the kernel 19 22 static psKernel *convolveStamp(const pmSubtractionStamp *stamp, // Stamp to be convolved -
trunk/psModules/src/imcombine/pmSubtractionStamps.c
r29543 r30622 27 27 #include "pmSource.h" 28 28 29 #include "pmSubtractionTypes.h" 29 30 #include "pmSubtraction.h" 30 31 #include "pmSubtractionStamps.h" 32 #include "pmSubtractionVisual.h" 31 33 32 34 #define STAMP_LIST_BUFFER 20 // Number of stamps to add to list at a time … … 122 124 if ((image1 && image1->data.F32[y][x] < thresh1) || 123 125 (image2 && image2->data.F32[y][x] < thresh2)) { 126 // fprintf (stderr, "%f,%f : thresh\n", xRaw, yRaw); 124 127 continue; 125 128 } … … 366 369 } 367 370 368 369 pmSubtractionStampList *pmSubtractionStampsFind(pmSubtractionStampList *stamps, const psImage *image1, 370 const psImage *image2, const psImage *subMask, 371 const psRegion *region, float thresh1, float thresh2, 372 int size, int footprint, float spacing, float normFrac, 373 float sysErr, float skyErr, pmSubtractionMode mode) 371 bool pmSubtractionStampsSelect(pmSubtractionStampList **stamps, // Stamps to read 372 const pmReadout *ro1, // Readout 1 373 const pmReadout *ro2, // Readout 2 374 const psImage *subMask, // Mask for subtraction, or NULL 375 psImage *variance, // Variance map 376 const psRegion *region, // Region of interest 377 float thresh1, // Threshold for stamp finding on readout 1 378 float thresh2, // Threshold for stamp finding on readout 2 379 float stampSpacing, // Spacing between stamps 380 float normFrac, // Fraction of flux in window for normalisation window 381 float sysError, // Relative systematic error in images 382 float skyError, // Relative systematic error in images 383 int size, // Kernel half-size 384 int footprint, // Convolution footprint for stamps 385 pmSubtractionMode mode // Mode for subtraction 386 ) 387 { 388 PS_ASSERT_PTR_NON_NULL(stamps, false); 389 PM_ASSERT_READOUT_NON_NULL(ro1, false); 390 PM_ASSERT_READOUT_NON_NULL(ro2, false); 391 PS_ASSERT_IMAGE_NON_NULL(subMask, false); 392 PS_ASSERT_IMAGE_NON_NULL(variance, false); 393 PS_ASSERT_PTR_NON_NULL(region, false); 394 395 psTrace("psModules.imcombine", 3, "Finding stamps...\n"); 396 397 psImage *image1 = ro1 ? ro1->image : NULL, *image2 = ro2 ? ro2->image : NULL; // Images of interest 398 399 *stamps = pmSubtractionStampsFind(*stamps, image1, image2, subMask, region, thresh1, thresh2, 400 size, footprint, stampSpacing, normFrac, sysError, skyError, mode); 401 if (!*stamps) { 402 psError(psErrorCodeLast(), false, "Unable to find stamps."); 403 return false; 404 } 405 406 psTrace("psModules.imcombine", 3, "Extracting stamps...\n"); 407 if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2->image, variance, size, *region)) { 408 psError(psErrorCodeLast(), false, "Unable to extract stamps."); 409 return false; 410 } 411 412 pmSubtractionVisualPlotStamps(*stamps, (pmReadout *) ro1); 413 return true; 414 } 415 416 pmSubtractionStampList *pmSubtractionStampsFind(pmSubtractionStampList *stamps, 417 const psImage *image1, 418 const psImage *image2, 419 const psImage *subMask, 420 const psRegion *region, 421 float thresh1, 422 float thresh2, 423 int size, 424 int footprint, 425 float spacing, 426 float normFrac, 427 float sysErr, 428 float skyErr, 429 pmSubtractionMode mode) 374 430 { 375 431 if (!image1 && !image2) { … … 429 485 stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing, 430 486 normFrac, sysErr, skyErr); 487 } 488 489 // XXX TEST : dump all stars in the stamps here 490 if (0) { 491 FILE *f = fopen ("stamp.dat", "w"); 492 for (int i = 0; i < stamps->num; i++) { 493 psVector *xList = stamps->x->data[i]; 494 psVector *yList = stamps->y->data[i]; // Coordinate lists 495 psVector *fluxList = stamps->flux->data[i]; // List of stamp fluxes 496 497 for (int j = 0; j < xList->n; j++) { 498 fprintf (f, "%d %d %f %f %f\n", i, j, xList->data.F32[j], yList->data.F32[j], fluxList->data.F32[j]); 499 } 500 } 501 fclose (f); 431 502 } 432 503 … … 636 707 } 637 708 709 int nTotal = 0; 710 638 711 // Sort the list by flux, with the brightest last 639 712 for (int i = 0; i < numStamps; i++) { … … 662 735 stamps->y->data[i] = ySorted; 663 736 stamps->flux->data[i] = fluxSorted; 664 } 665 737 nTotal += num; 738 } 739 // fprintf (stderr, "nTotal %d\n", nTotal); 740 666 741 return stamps; 667 742 } 668 743 669 670 bool pmSubtractionStampsGetWindow(pmSubtractionStampList *stamps, int kernelSize) 744 // we are essentially using aperture photometry to determine the photometric match between the 745 // images. we need to choose an appropriate-sized aperture for this analysis. If it is too 746 // large, the measurement will be noisy (and possibly biased) due to the sky noise. If it is 747 // too small, or inconsistent, the measurement will be biased. We use Kron-mag like aperture 748 // scaled by the first radial moment. 749 bool pmSubtractionStampsGetWindow(bool *tryAgain, pmSubtractionStampList *stamps, int kernelSize) 671 750 { 672 751 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); 673 752 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 674 753 754 // if we succeed, or fail with an unrecoverable error, do not try again 755 if (tryAgain) { 756 *tryAgain = false; 757 } 758 675 759 int size = stamps->footprint; // Size of postage stamps 676 760 761 // window for moments calculations downstream 762 psFree (stamps->window); 763 stamps->window = psKernelAlloc(-size, size, -size, size); 764 psImageInit(stamps->window->image, 0.0); 765 766 // window1 and window2 are mean stamp images used here to measure the 767 // first radial moment, and thus the normalization window 677 768 psFree (stamps->window1); 678 769 stamps->window1 = psKernelAlloc(-size, size, -size, size); … … 683 774 psImageInit(stamps->window2->image, 0.0); 684 775 685 // Generate a weighting window based on the fwhms (20% larger than the largest) 686 { 687 float fwhm1, fwhm2; 688 689 // XXX this is annoyingly hack-ish 690 pmSubtractionGetFWHMs(&fwhm1, &fwhm2); 691 692 float sigma = 1.5 * PS_MAX(fwhm1, fwhm2) / 2.35; 693 694 psFree (stamps->window); 695 stamps->window = psKernelAlloc(-size, size, -size, size); 696 psImageInit(stamps->window->image, 0.0); 697 698 for (int y = -size; y <= size; y++) { 699 for (int x = -size; x <= size; x++) { 700 stamps->window->kernel[y][x] = exp(-0.5*(x*x + y*y)/(sigma*sigma)); 701 } 702 } 776 // Generate an initial weighting window based on the fwhms (50% larger than the largest) 777 float fwhm1, fwhm2; 778 779 // XXX this is annoyingly hack-ish 780 pmSubtractionGetFWHMs(&fwhm1, &fwhm2); 781 782 float sigma = 1.5 * PS_MAX(fwhm1, fwhm2) / 2.35; 783 784 for (int y = -size; y <= size; y++) { 785 for (int x = -size; x <= size; x++) { 786 stamps->window->kernel[y][x] = exp(-0.5*(x*x + y*y)/(sigma*sigma)); 787 } 703 788 } 704 789 … … 790 875 psTrace("psModules.imcombine", 3, "Window total (2): %f, threshold: %f\n", sum2, (1.0 - stamps->normFrac) * sum2); 791 876 792 # if (1) 793 // this block attempts to calculate the radius based on the first radial moment 877 // attempt to calculate the normalization window based on the first radial moment 794 878 double Sr1 = 0.0; 795 879 double Sr2 = 0.0; … … 809 893 float R2 = Sr2 / Sf2; 810 894 811 stamps->normWindow1 = 2.0*R1; 812 stamps->normWindow2 = 2.0*R2; 813 psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Kron Radii: %f for 1, %f for 2\n", stamps->normWindow1, stamps->normWindow2); 814 815 # else 816 // XXX : this block attempts to calculate the radius by looking at the curve of growth (or something vaguely equivalent). 817 // It did not do very well (though a true curve-of-growth analysis might be better...) 818 bool done1 = false; 819 bool done2 = false; 820 double prior1 = 0.0; 821 double prior2 = 0.0; 822 double delta1o = 1.0; 823 double delta2o = 1.0; 824 for (int radius = 1; radius <= size && !(done1 && done2); radius++) { 825 double within1 = 0.0; 826 double within2 = 0.0; 827 for (int y = -radius; y <= radius; y++) { 828 for (int x = -radius; x <= radius; x++) { 829 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) { 830 within1 += stamps->window1->kernel[y][x]; 831 } 832 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) { 833 within2 += stamps->window2->kernel[y][x]; 834 } 835 } 836 } 837 double delta1 = (within1 - prior1) / within1; 838 if (!done1 && (fabs(delta1) < stamps->normFrac)) { 839 // interpolate to the radius at which delta2 is normFrac: 840 stamps->normWindow1 = radius - (stamps->normFrac - delta1) / (delta1o - delta1); 841 psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "choosing %f (%d) for 1 (%f : %f)\n", stamps->normWindow1, radius, within1, delta1); 842 done1 = true; 843 } 844 double delta2 = (within2 - prior2) / within2; 845 if (!done2 && (fabs(delta2) < stamps->normFrac)) { 846 // interpolate to the radius at which delta2 is normFrac: 847 stamps->normWindow2 = radius - (stamps->normFrac - delta2) / (delta2o - delta2); 848 psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "choosing %f (%d) for 2 (%f : %f)\n", stamps->normWindow2, radius, within2, delta2); 849 done2 = true; 850 } 851 psTrace("psModules.imcombine", 5, "Radius %d: %f (%f) and %f (%f)\n", radius, within1, delta1, within2, delta2); 852 853 prior1 = within1; 854 prior2 = within2; 855 delta1o = delta1; 856 delta2o = delta2; 857 858 // if (!done1 && (within1 > (1.0 - stamps->normFrac) * sum1)) { 859 // stamps->normWindow1 = radius; 860 // done1 = true; 861 // } 862 // if (!done2 && (within2 > (1.0 - stamps->normFrac) * sum2)) { 863 // stamps->normWindow2 = radius; 864 // done2 = true; 865 // } 866 867 } 868 # endif 869 870 psTrace("psModules.imcombine", 3, "Normalisation window radii set to %f and %f\n", stamps->normWindow1, stamps->normWindow2); 871 if (stamps->normWindow1 == 0 || stamps->normWindow1 >= size) { 895 // Compare the Kron Radii (R1 & R2) to above to the FWHMs : if they are too discrepant, we will need to rescale 896 psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Kron Radii vs FWHMs 1: fwhm: %f, kron %f\n", fwhm1, R1); 897 psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Kron Radii vs FWHMs 2: fwhm: %f, kron %f\n", fwhm2, R2); 898 899 // XXX CAREFUL : in pmSubtractionMatch.c:703, we rely on this factor of 2.75.. 900 stamps->normWindow1 = 2.75*R1; 901 stamps->normWindow2 = 2.75*R2; 902 psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Windows from Kron Radii: %f for 1, %f for 2\n", stamps->normWindow1, stamps->normWindow2); 903 904 // if the calculated normWindows are too large, we will fall off the stamps. In this case, we need to try again. 905 if ((stamps->normWindow1 > size) || (stamps->normWindow2 > size)) { 906 if (tryAgain) { 907 *tryAgain = true; 908 } 909 psFree (stats); 910 psFree (flux1); 911 psFree (flux2); 912 psFree (norm1); 913 psFree (norm2); 914 return false; 915 } 916 917 // this is an unrecoverable error : something really bogus in the data 918 if (stamps->normWindow1 == 0) { 872 919 psError(PM_ERR_STAMPS, true, "Unable to determine normalisation window size (1)."); 920 psFree (stats); 921 psFree (flux1); 922 psFree (flux2); 923 psFree (norm1); 924 psFree (norm2); 873 925 return false; 874 926 } 875 if (stamps->normWindow2 == 0 || stamps->normWindow2 >= size) {927 if (stamps->normWindow2 == 0) { 876 928 psError(PM_ERR_STAMPS, true, "Unable to determine normalisation window size (2)."); 929 psFree (stats); 930 psFree (flux1); 931 psFree (flux2); 932 psFree (norm1); 933 psFree (norm2); 877 934 return false; 935 } 936 937 // Generate a weighting window based on the kron radii 938 float radius = 2.0 * PS_MAX(R1, R2); 939 psImageInit(stamps->window->image, 0.0); 940 941 // we use a top-hat window for the moments analysis 942 for (int y = -size; y <= size; y++) { 943 for (int x = -size; x <= size; x++) { 944 if (hypot(x,y) > radius) continue; 945 stamps->window->kernel[y][x] = 1.0; 946 } 878 947 } 879 948 … … 890 959 } 891 960 } 892 893 #if 0894 {895 psFits *fits = NULL;896 fits = psFitsOpen ("window1.norm.fits", "w");897 psFitsWriteImage (fits, NULL, stamps->window1->image, 0, NULL);898 psFitsClose (fits);899 fits = psFitsOpen ("window2.norm.fits", "w");900 psFitsWriteImage (fits, NULL, stamps->window2->image, 0, NULL);901 psFitsClose (fits);902 }903 #endif904 961 905 962 psFree (stats); … … 1128 1185 continue; 1129 1186 } 1187 1188 // XXX this is somewhat arbitrary... 1189 if (source->errMag > 0.05) continue; 1190 if (fabs(source->psfMag - source->apMag) > 0.5) continue; 1191 1130 1192 if (source->modelPSF) { 1131 1193 x->data.F32[numOut] = source->modelPSF->params->data.F32[PM_PAR_XPOS]; … … 1135 1197 y->data.F32[numOut] = source->peak->yf; 1136 1198 } 1137 // fprintf (stderr, "stamp: %5.1f %5.1f\n", x->data.F32[numOut], y->data.F32[numOut]);1138 1199 numOut++; 1139 1200 } -
trunk/psModules/src/imcombine/pmSubtractionStamps.h
r29543 r30622 1 1 #ifndef PM_SUBTRACTION_STAMPS_H 2 2 #define PM_SUBTRACTION_STAMPS_H 3 4 #include <pslib.h>5 6 #include "pmSubtractionKernels.h"7 8 /// Status of stamp9 typedef enum {10 PM_SUBTRACTION_STAMP_INIT, ///< Initial state11 PM_SUBTRACTION_STAMP_FOUND, ///< Found a suitable source for this stamp12 PM_SUBTRACTION_STAMP_CALCULATE, ///< Calculate matrix and vector values for this stamp13 PM_SUBTRACTION_STAMP_USED, ///< Use this stamp14 PM_SUBTRACTION_STAMP_REJECTED, ///< This stamp has been rejected15 PM_SUBTRACTION_STAMP_NONE ///< No stamp in this region16 } pmSubtractionStampStatus;17 18 /// A list of stamps19 typedef struct {20 long num; ///< Number of stamps21 psArray *stamps; ///< The stamps22 psArray *regions; ///< Regions for each stamp23 psArray *x, *y; ///< Coordinates for possible stamps (or NULL)24 psArray *flux; ///< Fluxes for possible stamps (or NULL)25 int footprint; ///< Half-size of stamps26 float normFrac; ///< Fraction of flux in window for normalisation window27 float normValue; ///< calculated normalization28 float normValue2; ///< calculated normalization29 psKernel *window1; ///< window function generated from ensemble of stamps (input 1)30 psKernel *window2; ///< window function generated from ensemble of stamps (input 2)31 psKernel *window; ///< weighting window function (sigma = 1.1 * MAX(fwhm))32 float normWindow1; ///< Size of window for measuring normalisation33 float normWindow2; ///< Size of window for measuring normalisation34 float sysErr; ///< Systematic error35 float skyErr; ///< increase effective readnoise36 } pmSubtractionStampList;37 3 38 4 /// Allocate a list of stamps … … 74 40 ); 75 41 76 77 /// A stamp for image subtraction78 typedef struct {79 float x, y; ///< Position80 float flux; ///< Flux81 float xNorm, yNorm; ///< Normalised position82 psKernel *image1; ///< Reference image postage stamp83 psKernel *image2; ///< Input image postage stamp84 psKernel *weight; ///< Weight image (1/variance) postage stamp, or NULL85 psArray *convolutions1; ///< Convolutions of image 1 for each kernel component, or NULL86 psArray *convolutions2; ///< Convolutions of image 2 for each kernel component, or NULL87 psImage *matrix; ///< Least-squares matrix, or NULL88 psVector *vector; ///< Least-squares vector, or NULL89 double norm; ///< Normalisation difference90 double normI1; ///< Sum(flux) for image 191 double normI2; ///< Sum(flux) for image 292 double normSquare1; ///< Sum(flux^2) for image 1 (used for penalty)93 double normSquare2; ///< Sum(flux^2) for image 2 (used for penalty)94 pmSubtractionStampStatus status; ///< Status of stamp95 psVector *MxxI1; ///< second moments of convolution images96 psVector *MyyI1; ///< second moments of convolution images97 psVector *MxxI2; ///< second moments of convolution images98 psVector *MyyI2; ///< second moments of convolution images99 double MxxI1raw;100 double MyyI1raw;101 double MxxI2raw;102 double MyyI2raw;103 } pmSubtractionStamp;104 105 42 /// Allocate a stamp 106 43 pmSubtractionStamp *pmSubtractionStampAlloc(void); 44 45 // find and extract the stamps 46 bool pmSubtractionStampsSelect(pmSubtractionStampList **stamps, // Stamps to read 47 const pmReadout *ro1, // Readout 1 48 const pmReadout *ro2, // Readout 2 49 const psImage *subMask, // Mask for subtraction, or NULL 50 psImage *variance, // Variance map 51 const psRegion *region, // Region of interest 52 float thresh1, // Threshold for stamp finding on readout 1 53 float thresh2, // Threshold for stamp finding on readout 2 54 float stampSpacing, // Spacing between stamps 55 float normFrac, // Fraction of flux in window for normalisation window 56 float sysError, // Relative systematic error in images 57 float skyError, // Relative systematic error in images 58 int size, // Kernel half-size 59 int footprint, // Convolution footprint for stamps 60 pmSubtractionMode mode // Mode for subtraction 61 ); 62 107 63 108 64 /// Find stamps on an image … … 172 128 /// Calculate the window and normalisation window from the stamps 173 129 bool pmSubtractionStampsGetWindow( 130 bool *tryAgain, ///< re-try with new stamp size? 174 131 pmSubtractionStampList *stamps, ///< List of stamps 175 132 int kernelSize ///< Half-size of kernel -
trunk/psModules/src/imcombine/pmSubtractionThreads.c
r27365 r30622 6 6 #include <pslib.h> 7 7 8 #include "pmSubtractionTypes.h" 8 9 #include "pmSubtractionMatch.h" 9 10 #include "pmSubtractionEquation.h" … … 33 34 34 35 { 35 psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 4);36 psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 3); 36 37 task->function = &pmSubtractionCalculateEquationThread; 38 psThreadTaskAdd(task); 39 psFree(task); 40 } 41 42 { 43 psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CONVOLVE_STAMP", 3); 44 task->function = &pmSubtractionConvolveStampThread; 37 45 psThreadTaskAdd(task); 38 46 psFree(task); -
trunk/psModules/src/imcombine/pmSubtractionTypes.h
r30585 r30622 80 80 int xMin, xMax, yMin, yMax; ///< Bounds of image (for normalisation) 81 81 long num; ///< Number of kernel components (not including the spatial ones) 82 psVector *fwhms; ///< requested fwhms of the kernel Gaussians (ISIS, HERM or DECONV_HERM) 83 psVector *orders; ///< polynomial orders for each Gaussian (ISIS, HERM or DECONV_HERM) 82 84 psVector *u, *v; ///< Offset (for POIS) or polynomial order (for ISIS, HERM or DECONV_HERM) 83 psVector *widths; ///< Gaussian FWHMs(ISIS, HERM or DECONV_HERM)85 psVector *widths; ///< measured Gaussian FWHMs of Gauss*poly (ISIS, HERM or DECONV_HERM) 84 86 psVector *uStop, *vStop; ///< Width of kernel element (SPAM,FRIES only) 85 87 psArray *preCalc; ///< Array of images containing pre-calculated kernel (for ISIS, HERM or DECONV_HERM) … … 90 92 int size; ///< The half-size of the kernel 91 93 int inner; ///< The size of an inner region 94 int binning; ///< Binning used for the SPAM kernels 95 int ringsOrder; ///< 92 96 int spatialOrder; ///< The spatial order of the kernels 93 97 int bgOrder; ///< The order for the background fitting -
trunk/psModules/src/imcombine/pmSubtractionVisual.c
r29600 r30622 16 16 17 17 #include "pmKapaPlots.h" 18 #include "pmFPA.h" 19 #include "pmSubtractionTypes.h" 18 20 #include "pmSubtraction.h" 19 21 #include "pmSubtractionStamps.h" 20 22 #include "pmSubtractionEquation.h" 21 23 #include "pmSubtractionKernels.h" 24 #include "pmSubtractionVisual.h" 22 25 23 26 #include "pmVisual.h" … … 210 213 psImageOverlaySection(canvas, im, x0, y0, "="); 211 214 stampNum++; 215 216 // renormalize the section 217 float maxValue = 0; 218 for (int iy = 0; iy < im->numRows; iy++) { 219 for (int ix = 0; ix < im->numCols; ix++) { 220 maxValue = PS_MAX(maxValue, im->data.F64[iy][ix]); 221 } 222 } 223 if (maxValue == 0.0) continue; 224 for (int iy = 0; iy < im->numRows; iy++) { 225 for (int ix = 0; ix < im->numCols; ix++) { 226 canvas->data.F64[y0 + iy][x0 + ix] /= maxValue; 227 } 228 } 212 229 } 213 230 … … 231 248 } 232 249 250 /** Plot the least-squares matrix of each stamp */ 251 bool pmSubtractionVisualPlotLeastSquaresResid (const pmSubtractionStampList *stamps, psImage *matrixIn, int nUsed) { 252 253 if (!pmVisualTestLevel("ppsub.chisq", 1)) return true; 254 255 if (!plotLeastSquares) return true; 256 257 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 258 return false; 259 } 260 261 psImage *matrixNorm = psImageCopy(NULL, matrixIn, PS_TYPE_F64); 262 { 263 // renormalize the matrix 264 float maxValue = 0; 265 for (int iy = 0; iy < matrixNorm->numRows; iy++) { 266 for (int ix = 0; ix < matrixNorm->numCols; ix++) { 267 maxValue = PS_MAX(maxValue, matrixNorm->data.F64[iy][ix]); 268 } 269 } 270 for (int iy = 0; iy < matrixNorm->numRows; iy++) { 271 for (int ix = 0; ix < matrixNorm->numCols; ix++) { 272 matrixNorm->data.F64[iy][ix] /= maxValue; 273 } 274 } 275 } 276 277 // Find the stamp size 278 int imageMax = -1; 279 int numStamps = 0; 280 psElemType type = PS_TYPE_F64; 281 282 for(int i = 0; i < stamps->num; i++) { 283 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 284 if (stamp == NULL) continue; 285 286 psImage *im = stamp->matrix; 287 if (im == NULL) continue; 288 289 imageMax = PS_MAX(imageMax, im->numCols); 290 imageMax = PS_MAX(imageMax, im->numRows); 291 numStamps++; 292 type = im->type.type; 293 } 294 if (imageMax == -1) return false; 295 296 int border = 15; 297 imageMax += border; 298 int tileRowCount = (int) ceil(sqrt(numStamps)); 299 int canvasX = tileRowCount * (imageMax); 300 int canvasY = tileRowCount * (imageMax); 301 psImage *canvas = psImageAlloc (canvasX, canvasY, type); 302 psImageInit (canvas, NAN); 303 304 // overlay the images 305 int stampNum = 0; 306 int stampListNum = 0; 307 while (stampNum < numStamps) { 308 int x0 = (imageMax) * (stampNum % tileRowCount); 309 int y0 = (imageMax) * (stampNum / tileRowCount); 310 311 pmSubtractionStamp *stamp = stamps->stamps->data[stampListNum++]; 312 if (stamp == NULL) continue; 313 314 psImage *im = stamp->matrix; 315 if (im == NULL) continue; 316 317 stampNum++; 318 319 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 320 321 // renormalize the section 322 float maxValue = 0; 323 for (int iy = 0; iy < im->numRows; iy++) { 324 for (int ix = 0; ix < im->numCols; ix++) { 325 maxValue = PS_MAX(maxValue, im->data.F64[iy][ix]); 326 } 327 } 328 if (maxValue == 0.0) continue; 329 for (int iy = 0; iy < im->numRows; iy++) { 330 for (int ix = 0; ix < im->numCols; ix++) { 331 canvas->data.F64[y0 + iy][x0 + ix] = (im->data.F64[iy][ix] / maxValue - matrixNorm->data.F64[iy][ix]) / matrixNorm->data.F64[iy][ix]; 332 } 333 } 334 } 335 336 psImage *canvas32 = pmVisualImageToFloat(canvas); 337 pmVisualRangeImage(kapa2, canvas32, "Least_Squares", 0, -100.0, 100.0); 338 339 if (0) { 340 static int count = 0; 341 char filename[64]; 342 sprintf (filename, "chisq.%02d.fits", count); 343 count ++; 344 psFits *fits = psFitsOpen (filename, "w"); 345 psFitsWriteImage (fits, NULL, canvas32, 0, NULL); 346 psFitsClose (fits); 347 } 348 349 pmVisualAskUser(&plotLeastSquares); 350 psFree(canvas); 351 psFree(canvas32); 352 return true; 353 } 354 233 355 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub) { 234 356 … … 304 426 } 305 427 306 // XXX clear the overlay(s) (red at least!) 428 // clear the overlay (red at least!) 429 KiiEraseOverlay (kapa2, "red"); 307 430 308 431 // get the kernel sizes … … 337 460 int nKernels = 0; 338 461 462 // paste in the kernel images, scaled by sum2 339 463 if (maxStamp->convolutions1) { 340 464 // output image is a grid of NXsub by NYsub sub-images … … 359 483 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 360 484 361 double sum = 0.0;362 485 double sum2 = 0.0; 363 486 for (int y = -footprint; y <= footprint; y++) { 364 487 for (int x = -footprint; x <= footprint; x++) { 365 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x];366 sum += kernel->kernel[y][x];367 488 sum2 += PS_SQR(kernel->kernel[y][x]); 368 489 } 369 490 } 370 // fprintf (stderr, "kernel %d, sum %f, sum2: %e\n", i, sum, sum2); 491 float scale = sqrt(sum2) / PS_SQR(2*footprint + 1); 492 for (int y = -footprint; y <= footprint; y++) { 493 for (int x = -footprint; x <= footprint; x++) { 494 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x] / scale; 495 } 496 } 371 497 } 372 498 pmVisualScaleImage(kapa2, output, "Image", 0, true); … … 401 527 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 402 528 403 double sum = 0.0;404 529 double sum2 = 0.0; 405 530 for (int y = -footprint; y <= footprint; y++) { 406 531 for (int x = -footprint; x <= footprint; x++) { 407 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x];408 sum += kernel->kernel[y][x];409 532 sum2 += PS_SQR(kernel->kernel[y][x]); 410 533 } 411 534 } 412 // fprintf (stderr, "kernel %d, sum %f, sum2: %e\n", i, sum, sum2); 535 float scale = sqrt(sum2) / PS_SQR(2*footprint + 1); 536 for (int y = -footprint; y <= footprint; y++) { 537 for (int x = -footprint; x <= footprint; x++) { 538 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x] / scale; 539 } 540 } 413 541 } 414 542 pmVisualScaleImage(kapa2, output, "Image", 1, true); … … 468 596 KiiLoadOverlay (kapa2, overlay, Noverlay, "red"); 469 597 FREE (overlay); 470 return true;471 }472 473 static int footprint = 0;474 static int NX = 0;475 static int NY = 0;476 static psImage *sourceImage = NULL;477 static psImage *targetImage = NULL;478 static psImage *residualImage = NULL;479 static psImage *fresidualImage = NULL;480 static psImage *differenceImage = NULL;481 static psImage *convolutionImage = NULL;482 483 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) {484 485 if (!pmVisualTestLevel("ppsub.fit", 1)) return true;486 487 // generate 4 storage images large enough to hold the N stamps:488 489 footprint = stamps->footprint;490 491 float NXf = sqrt(stamps->num);492 NX = (int) NXf == NXf ? NXf : NXf + 1.0;493 494 float NYf = stamps->num / NX;495 NY = (int) NYf == NY ? NYf : NYf + 1.0;496 497 int NXpix = (2*footprint + 1) * NX;498 NXpix += (NX > 1) ? 3 * NX : 0;499 500 int NYpix = (2*footprint + 1) * NY;501 NYpix += (NY > 1) ? 3 * NY : 0;502 503 sourceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);504 targetImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);505 residualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);506 fresidualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);507 differenceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);508 convolutionImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);509 510 psImageInit (sourceImage, 0.0);511 psImageInit (targetImage, 0.0);512 psImageInit (residualImage, 0.0);513 psImageInit (fresidualImage, 0.0);514 psImageInit (differenceImage, 0.0);515 psImageInit (convolutionImage, 0.0);516 517 return true;518 }519 520 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) {521 522 if (!pmVisualTestLevel("ppsub.stamp", 1)) return true;523 524 double sum;525 526 int NXoff = index % NX;527 int NYoff = index / NX;528 529 int NXpix = NXoff * (2*footprint + 1 + 3) + footprint;530 int NYpix = NYoff * (2*footprint + 1 + 3) + footprint;531 532 // insert the (target) kernel into the (target) image:533 sum = 0.0;534 for (int y = -footprint; y <= footprint; y++) {535 for (int x = -footprint; x <= footprint; x++) {536 targetImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x];537 sum += targetImage->data.F32[y + NYpix][x + NXpix];538 }539 }540 targetImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;541 542 // insert the (source) kernel into the (source) image:543 sum = 0.0;544 for (int y = -footprint; y <= footprint; y++) {545 for (int x = -footprint; x <= footprint; x++) {546 sourceImage->data.F32[y + NYpix][x + NXpix] = source->kernel[y][x];547 sum += sourceImage->data.F32[y + NYpix][x + NXpix];548 }549 }550 sourceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;551 552 // insert the (convolution) kernel into the (convolution) image:553 sum = 0.0;554 for (int y = -footprint; y <= footprint; y++) {555 for (int x = -footprint; x <= footprint; x++) {556 convolutionImage->data.F32[y + NYpix][x + NXpix] = convolution->kernel[y][x];557 sum += convolutionImage->data.F32[y + NYpix][x + NXpix];558 }559 }560 convolutionImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;561 562 // insert the (difference) kernel into the (difference) image:563 sum = 0.0;564 for (int y = -footprint; y <= footprint; y++) {565 for (int x = -footprint; x <= footprint; x++) {566 differenceImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm;567 sum += differenceImage->data.F32[y + NYpix][x + NXpix];568 }569 }570 differenceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;571 572 // insert the (residual) kernel into the (residual) image:573 sum = 0.0;574 for (int y = -footprint; y <= footprint; y++) {575 for (int x = -footprint; x <= footprint; x++) {576 residualImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm - convolution->kernel[y][x];577 sum += residualImage->data.F32[y + NYpix][x + NXpix];578 }579 }580 residualImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;581 582 // insert the (fresidual) kernel into the (fresidual) image:583 for (int y = -footprint; y <= footprint; y++) {584 for (int x = -footprint; x <= footprint; x++) {585 fresidualImage->data.F32[y + NYpix][x + NXpix] = residualImage->data.F32[y + NYpix][x + NXpix] / sqrt(PS_MAX(target->kernel[y][x], 100.0));586 }587 }588 598 return true; 589 599 } … … 611 621 } 612 622 613 bool pmSubtractionVisualShowFit(double norm) { 614 615 // for testing, dump the residual image and exit 616 if (0) { 617 psMetadata *header = psMetadataAlloc();618 psMetadataAddF32 (header, PS_LIST_TAIL, "NORM", 0, "Normalization", norm);619 psFits *fits = psFitsOpen("resid.fits", "w");620 psFitsWriteImage(fits, header, residualImage, 0, NULL);621 psFitsClose(fits);622 // exit (0); 623 } 623 static int footprint = 0; 624 static int NX = 0; 625 static int NY = 0; 626 static psImage *sourceImage = NULL; 627 static psImage *targetImage = NULL; 628 static psImage *residualImage = NULL; 629 static psImage *fresidualImage = NULL; 630 static psImage *differenceImage = NULL; 631 static psImage *convolutionImage = NULL; 632 633 bool pmSubtractionVisualShowFit(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels) { 624 634 625 635 if (!pmVisualTestLevel("ppsub.fit", 1)) return true; … … 627 637 if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) return false; 628 638 if (!pmVisualInitWindow(&kapa2, "ppSub:Misc")) return false; 639 640 // set up holding images for the visualization 641 pmSubtractionVisualShowFitInit (stamps); 642 643 int numKernels = kernels->num; // Number of kernels 644 645 psImage *polyValues = NULL; // Polynomial values 646 psKernel *residual = psKernelAlloc(-stamps->footprint, stamps->footprint, -stamps->footprint, stamps->footprint); // Residual image 647 648 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 649 650 for (int i = 0; i < stamps->num; i++) { 651 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest 652 if (stamp->status != PM_SUBTRACTION_STAMP_USED) { continue; } 653 654 // Calculate coefficients of the kernel basis functions 655 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm); 656 double background = p_pmSubtractionSolutionBackground(kernels, polyValues); // Difference in background 657 658 psImageInit(residual->image, 0.0); 659 660 if (kernels->mode != PM_SUBTRACTION_MODE_DUAL) { 661 psKernel *target; // Target postage stamp 662 psKernel *source; // Source postage stamp 663 psArray *convolutions; // Convolution postage stamps for each kernel basis function 664 switch (kernels->mode) { 665 case PM_SUBTRACTION_MODE_1: 666 target = stamp->image2; 667 source = stamp->image1; 668 convolutions = stamp->convolutions1; 669 break; 670 case PM_SUBTRACTION_MODE_2: 671 target = stamp->image1; 672 source = stamp->image2; 673 convolutions = stamp->convolutions2; 674 break; 675 default: 676 psAbort("Unsupported subtraction mode: %x", kernels->mode); 677 } 678 679 for (int j = 0; j < numKernels; j++) { 680 psKernel *convolution = convolutions->data[j]; // Convolution 681 double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 682 for (int y = - footprint; y <= footprint; y++) { 683 for (int x = - footprint; x <= footprint; x++) { 684 residual->kernel[y][x] += convolution->kernel[y][x] * coefficient; 685 } 686 } 687 } 688 // visualize the target, source, convolution and residual 689 pmSubtractionVisualShowFitAddStamp (target, source, residual, background, norm, i); 690 } else { 691 // Dual convolution 692 psArray *convolutions1 = stamp->convolutions1; // Convolutions of the first image 693 psArray *convolutions2 = stamp->convolutions2; // Convolutions of the second image 694 psKernel *image1 = stamp->image1; // The first image 695 psKernel *image2 = stamp->image2; // The second image 696 697 for (int j = 0; j < numKernels; j++) { 698 psKernel *conv1 = convolutions1->data[j]; // Convolution of first image 699 psKernel *conv2 = convolutions2->data[j]; // Convolution of second image 700 double coeff1 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1 701 double coeff2 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, true); // Coefficient 2 702 703 for (int y = - footprint; y <= footprint; y++) { 704 for (int x = - footprint; x <= footprint; x++) { 705 residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 + conv1->kernel[y][x] * coeff1; 706 } 707 } 708 } 709 // visualize the target, source, convolution and residual 710 pmSubtractionVisualShowFitAddStamp (image2, image1, residual, background, norm, i); 711 } 712 } 713 pmSubtractionVisualShowFitImage(norm); 714 715 return true; 716 } 717 718 // generate 4 storage images large enough to hold the stamps: 719 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) { 720 721 footprint = stamps->footprint; 722 723 float NXf = sqrt(stamps->num); 724 NX = (int) NXf == NXf ? NXf : NXf + 1.0; 725 726 float NYf = stamps->num / NX; 727 NY = (int) NYf == NY ? NYf : NYf + 1.0; 728 729 int NXpix = (2*footprint + 1) * NX; 730 NXpix += (NX > 1) ? 3 * NX : 0; 731 732 int NYpix = (2*footprint + 1) * NY; 733 NYpix += (NY > 1) ? 3 * NY : 0; 734 735 sourceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 736 targetImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 737 residualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 738 fresidualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 739 differenceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 740 convolutionImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 741 742 psImageInit (sourceImage, 0.0); 743 psImageInit (targetImage, 0.0); 744 psImageInit (residualImage, 0.0); 745 psImageInit (fresidualImage, 0.0); 746 psImageInit (differenceImage, 0.0); 747 psImageInit (convolutionImage, 0.0); 748 749 return true; 750 } 751 752 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) { 753 754 double sum; 755 756 int NXoff = index % NX; 757 int NYoff = index / NX; 758 759 int NXpix = NXoff * (2*footprint + 1 + 3) + footprint; 760 int NYpix = NYoff * (2*footprint + 1 + 3) + footprint; 761 762 // insert the (target) kernel into the (target) image: 763 sum = 0.0; 764 for (int y = -footprint; y <= footprint; y++) { 765 for (int x = -footprint; x <= footprint; x++) { 766 targetImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x]; 767 sum += targetImage->data.F32[y + NYpix][x + NXpix]; 768 } 769 } 770 targetImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 771 772 // insert the (source) kernel into the (source) image: 773 sum = 0.0; 774 for (int y = -footprint; y <= footprint; y++) { 775 for (int x = -footprint; x <= footprint; x++) { 776 sourceImage->data.F32[y + NYpix][x + NXpix] = source->kernel[y][x]; 777 sum += sourceImage->data.F32[y + NYpix][x + NXpix]; 778 } 779 } 780 sourceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 781 782 // insert the (convolution) kernel into the (convolution) image: 783 sum = 0.0; 784 for (int y = -footprint; y <= footprint; y++) { 785 for (int x = -footprint; x <= footprint; x++) { 786 convolutionImage->data.F32[y + NYpix][x + NXpix] = convolution->kernel[y][x]; 787 sum += convolutionImage->data.F32[y + NYpix][x + NXpix]; 788 } 789 } 790 convolutionImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 791 792 // insert the (difference) kernel into the (difference) image: 793 sum = 0.0; 794 for (int y = -footprint; y <= footprint; y++) { 795 for (int x = -footprint; x <= footprint; x++) { 796 differenceImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm; 797 sum += differenceImage->data.F32[y + NYpix][x + NXpix]; 798 } 799 } 800 differenceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 801 802 // insert the (residual) kernel into the (residual) image: 803 sum = 0.0; 804 for (int y = -footprint; y <= footprint; y++) { 805 for (int x = -footprint; x <= footprint; x++) { 806 residualImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm - convolution->kernel[y][x]; 807 sum += residualImage->data.F32[y + NYpix][x + NXpix]; 808 } 809 } 810 residualImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 811 812 // insert the (fresidual) kernel into the (fresidual) image: 813 for (int y = -footprint; y <= footprint; y++) { 814 for (int x = -footprint; x <= footprint; x++) { 815 fresidualImage->data.F32[y + NYpix][x + NXpix] = residualImage->data.F32[y + NYpix][x + NXpix] / sqrt(PS_MAX(target->kernel[y][x], 100.0)); 816 } 817 } 818 return true; 819 } 820 821 bool pmSubtractionVisualShowFitImage(double norm) { 629 822 630 823 KiiEraseOverlay (kapa1, "red"); … … 673 866 psVector *x = psVectorAllocEmpty (kernels->num, PS_TYPE_F32); 674 867 psVector *y = psVectorAllocEmpty (kernels->num, PS_TYPE_F32); 868 psVector *dy = psVectorAllocEmpty (kernels->num, PS_TYPE_F32); 675 869 676 870 graphdata.xmin = -1.0; … … 685 879 x->data.F32[i] = i; 686 880 y->data.F32[i] = p_pmSubtractionSolutionCoeff(kernels, polyValues, i, false); 881 dy->data.F32[i] = kernels->solution1err->data.F64[i]; 687 882 graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[i]); 688 883 graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[i]); 689 884 } 690 x->n = y->n = kernels->num;885 x->n = y->n = dy->n = kernels->num; 691 886 692 887 float range; … … 709 904 graphdata.size = 0.5; 710 905 graphdata.style = 2; 906 graphdata.etype |= 0x01; 711 907 712 908 KapaPrepPlot (kapa3, x->n, &graphdata); 713 909 KapaPlotVector (kapa3, x->n, x->data.F32, "x"); 714 910 KapaPlotVector (kapa3, x->n, y->data.F32, "y"); 911 KapaPlotVector (kapa3, x->n, dy->data.F32, "dym"); 912 KapaPlotVector (kapa3, x->n, dy->data.F32, "dyp"); 715 913 716 914 psFree (x); 717 915 psFree (y); 916 psFree (dy); 718 917 psFree (polyValues); 918 919 pmVisualAskUser(NULL); 920 return true; 921 } 922 923 // plot log(flux) vs log(chisq), log(flux) vs log(moments), log(chisq) vs log(moments) 924 bool pmSubtractionVisualPlotChisqAndMoments(psVector *fluxes, psVector *chisq, psVector *moments) { 925 926 Graphdata graphdata; 927 KapaSection section; 928 929 if (!pmVisualTestLevel("ppsub.fit", 1)) return true; 930 931 if (!pmVisualInitWindow(&kapa3, "ppSub:plots")) return false; 932 933 KapaClearSections (kapa3); 934 KapaInitGraph (&graphdata); 935 KiiResize(kapa3, 1500, 500); 936 937 psVector *lchi = psVectorAlloc (fluxes->n, PS_TYPE_F32); 938 psVector *lflx = psVectorAlloc (fluxes->n, PS_TYPE_F32); 939 psVector *lMxx = psVectorAlloc (fluxes->n, PS_TYPE_F32); 940 941 // construct the plot vectors 942 for (int i = 0; i < fluxes->n; i++) { 943 lchi->data.F32[i] = log10(chisq->data.F32[i]); 944 lflx->data.F32[i] = log10(fluxes->data.F32[i]); 945 lMxx->data.F32[i] = log10(moments->data.F32[i]); 946 } 947 948 section.bg = KapaColorByName ("none"); // XXX probably should be 'none' 949 950 // section 1: lflux vs lchi 951 section.dx = 0.33; 952 section.dy = 1.00; 953 section.x = 0.00; 954 section.y = 0.00; 955 section.name = psStringCopy ("flux.v.chi"); 956 KapaSetSection (kapa3, §ion); 957 psFree (section.name); 958 959 graphdata.color = KapaColorByName ("black"); 960 pmVisualScaleGraphdata(&graphdata, lflx, lchi, false); 961 KapaSetLimits (kapa3, &graphdata); 962 963 KapaSetFont (kapa3, "helvetica", 14); 964 KapaBox (kapa3, &graphdata); 965 KapaSendLabel (kapa3, "log(flux)", KAPA_LABEL_XM); 966 KapaSendLabel (kapa3, "log(chisq)", KAPA_LABEL_YM); 967 968 graphdata.color = KapaColorByName ("black"); 969 graphdata.ptype = 2; 970 graphdata.size = 0.5; 971 graphdata.style = 2; 972 973 KapaPrepPlot (kapa3, lflx->n, &graphdata); 974 KapaPlotVector (kapa3, lflx->n, lflx->data.F32, "x"); 975 KapaPlotVector (kapa3, lflx->n, lchi->data.F32, "y"); 976 977 // section 2: lflux vs lMxx 978 section.dx = 0.33; 979 section.dy = 1.00; 980 section.x = 0.33; 981 section.y = 0.00; 982 section.name = psStringCopy ("flux.v.mom"); 983 KapaSetSection (kapa3, §ion); 984 psFree (section.name); 985 986 graphdata.color = KapaColorByName ("black"); 987 pmVisualScaleGraphdata(&graphdata, lflx, lMxx, false); 988 KapaSetLimits (kapa3, &graphdata); 989 990 KapaSetFont (kapa3, "helvetica", 14); 991 KapaBox (kapa3, &graphdata); 992 KapaSendLabel (kapa3, "log(flux)", KAPA_LABEL_XM); 993 KapaSendLabel (kapa3, "log(moments)", KAPA_LABEL_YM); 994 995 graphdata.color = KapaColorByName ("black"); 996 graphdata.ptype = 2; 997 graphdata.size = 0.5; 998 graphdata.style = 2; 999 1000 KapaPrepPlot (kapa3, lflx->n, &graphdata); 1001 KapaPlotVector (kapa3, lflx->n, lflx->data.F32, "x"); 1002 KapaPlotVector (kapa3, lflx->n, lMxx->data.F32, "y"); 1003 1004 // section 1: lflux vs lchi 1005 section.dx = 0.33; 1006 section.dy = 1.00; 1007 section.x = 0.66; 1008 section.y = 0.00; 1009 section.name = psStringCopy ("chi.v.mom"); 1010 KapaSetSection (kapa3, §ion); 1011 psFree (section.name); 1012 1013 graphdata.color = KapaColorByName ("black"); 1014 pmVisualScaleGraphdata(&graphdata, lchi, lMxx, false); 1015 KapaSetLimits (kapa3, &graphdata); 1016 1017 KapaSetFont (kapa3, "helvetica", 14); 1018 KapaBox (kapa3, &graphdata); 1019 KapaSendLabel (kapa3, "log(chisq)", KAPA_LABEL_XM); 1020 KapaSendLabel (kapa3, "log(moments)", KAPA_LABEL_YM); 1021 1022 graphdata.color = KapaColorByName ("black"); 1023 graphdata.ptype = 2; 1024 graphdata.size = 0.5; 1025 graphdata.style = 2; 1026 1027 KapaPrepPlot (kapa3, lflx->n, &graphdata); 1028 KapaPlotVector (kapa3, lflx->n, lchi->data.F32, "x"); 1029 KapaPlotVector (kapa3, lflx->n, lMxx->data.F32, "y"); 719 1030 720 1031 pmVisualAskUser(NULL); -
trunk/psModules/src/imcombine/pmSubtractionVisual.h
r29601 r30622 6 6 bool pmSubtractionVisualPlotStamps(pmSubtractionStampList *stamps, pmReadout *ro); 7 7 bool pmSubtractionVisualPlotLeastSquares(pmSubtractionStampList *stamps); 8 bool pmSubtractionVisualPlotLeastSquaresResid (const pmSubtractionStampList *stamps, psImage *matrixIn, int nUsed); 8 9 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub); 10 11 bool pmSubtractionVisualShowFit(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels); 9 12 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps); 10 13 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index); 11 bool pmSubtractionVisualShowFit(double norm); 14 bool pmSubtractionVisualShowFitImage(double norm); 15 12 16 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels); 13 17 bool pmSubtractionVisualShowKernels(pmSubtractionKernels *kernels); 14 18 bool pmSubtractionVisualShowBasis(pmSubtractionStampList *stamps); 19 bool pmSubtractionVisualPlotChisqAndMoments(psVector *fluxes, psVector *chisq, psVector *moments); 15 20 16 21 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
