- Timestamp:
- Jan 17, 2011, 5:07:46 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-20101205/psModules/src/imcombine/pmSubtraction.c
r29777 r30288 773 773 774 774 if (convolutions) { 775 // Already done776 775 return convolutions; 777 776 } … … 787 786 } 788 787 788 789 bool pmSubtractionConvolveStampThread(psThreadJob *job) 790 { 791 PS_ASSERT_THREAD_JOB_NON_NULL(job, false); 792 793 pmSubtractionStamp *stamp = job->args->data[0]; // List of stamps 794 pmSubtractionKernels *kernels = job->args->data[1]; // Kernels 795 int footprint = PS_SCALAR_VALUE(job->args->data[2], S32); // Stamp index 796 797 return pmSubtractionConvolveStamp(stamp, kernels, footprint); 798 } 789 799 790 800 bool pmSubtractionConvolveStamp (pmSubtractionStamp *stamp, pmSubtractionKernels *kernels, int footprint) … … 818 828 } 819 829 830 #ifdef TESTING 831 for (int j = 0; j < kernels->num; j++) { 832 if (stamp->convolutions1) { 833 psString convName = NULL; 834 psStringAppend(&convName, "conv1_%03d_%03d.fits", index, j); 835 psFits *fits = psFitsOpen(convName, "w"); 836 psFree(convName); 837 psKernel *conv = stamp->convolutions1->data[j]; 838 psFitsWriteImage(fits, NULL, conv->image, 0, NULL); 839 psFitsClose(fits); 840 } 841 842 if (stamp->convolutions2) { 843 psString convName = NULL; 844 psStringAppend(&convName, "conv2_%03d_%03d.fits", index, j); 845 psFits *fits = psFitsOpen(convName, "w"); 846 psFree(convName); 847 psKernel *conv = stamp->convolutions2->data[j]; 848 psFitsWriteImage(fits, NULL, conv->image, 0, NULL); 849 psFitsClose(fits); 850 } 851 } 852 #endif 853 820 854 return true; 821 855 } 822 856 857 bool pmSubtractionConvolveStamps(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels) 858 { 859 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); 860 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); 861 862 psTimerStart("pmSubtractionConvolveStamps"); 863 864 int footprint = stamps->footprint; // Half-size of stamps 865 866 // We iterate over each stamp and generate the convolution if needed. We do NOT need the 867 // convolution if (a) it has already been calculated or (b) the stamp is not available for 868 // use (available = USED or CALCULATE) 869 870 for (int i = 0; i < stamps->num; i++) { 871 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 872 873 bool keep = false; 874 keep |= (stamp->status == PM_SUBTRACTION_STAMP_USED); 875 keep |= (stamp->status == PM_SUBTRACTION_STAMP_CALCULATE); 876 if (!keep) continue; 877 878 bool haveConvolutions = false; 879 if (kernels->mode == PM_SUBTRACTION_MODE_1) { 880 haveConvolutions = (stamp->convolutions1 != NULL); 881 } 882 if (kernels->mode == PM_SUBTRACTION_MODE_2) { 883 haveConvolutions = (stamp->convolutions2 != NULL); 884 } 885 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 886 haveConvolutions = (stamp->convolutions1 != NULL) && (stamp->convolutions2 != NULL); 887 } 888 if (haveConvolutions) { 889 continue; 890 } 891 892 if (pmSubtractionThreaded()) { 893 psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_CONVOLVE_STAMP"); 894 psArrayAdd(job->args, 1, stamp); 895 psArrayAdd(job->args, 1, kernels); 896 PS_ARRAY_ADD_SCALAR(job->args, footprint, PS_TYPE_S32); 897 if (!psThreadJobAddPending(job)) { 898 return false; 899 } 900 } else { 901 pmSubtractionConvolveStamp(stamp, kernels, footprint); 902 } 903 } 904 if (!psThreadPoolWait(true)) { 905 psError(psErrorCodeLast(), false, "Error waiting for threads."); 906 return false; 907 } 908 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolve stamps: %f sec", psTimerClear("pmSubtractionConvolveStamps")); 909 return true; 910 } 823 911 824 912 int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, pmSubtractionStampList *stamps, 825 const psVector *deviations, psImage *subMask, float sigmaRej)913 pmSubtractionQuality *match, psImage *subMask, float sigmaRej) 826 914 { 827 915 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); 828 916 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 917 PS_ASSERT_IMAGE_NON_EMPTY(subMask, -1); 832 918 PS_ASSERT_IMAGE_TYPE(subMask, PS_TYPE_IMAGE_MASK, -1); 833 919 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. 920 // Comment from PAP (r18287): I used to measure the rms deviation about zero, and use that as the 921 // sigma against which to clip, but the distribution is actually something like a chi^2 or 922 // Student's t, both of which become Gaussian-like with large N. Therefore, let's just 923 // treat this as a Gaussian distribution. 924 925 // Comment from EAM (r29777): The residual distribution is only chisq-like if the model is 926 // a good fit to the data. In the (likely) case that there is a systematic difference 927 // between the model and the data, the squared-residual distribution grows quadratically 928 // with increasing flux: the systematic residual flux is a constant factor times the source 929 // flux; the squared-residual is then of the form (k0 + k1*flux)^2, where k0 comes from the 930 // Gaussian distributed residual and k1*flux is the systematic residual error. 931 932 // By rejecting sources with the largest squared-residuals, the rejection biases against 933 // the brighter sources; in severe cases, this pushes the measurement to the weakest 934 // sources with the most noise. To account for this, let's fit a 2nd order polynomial to 935 // the distribution of flux vs squared-residual, subtract that fit, and reject sources 936 // which are significantly deviant from that distribution. 837 937 838 938 kernels->mean = NAN; … … 840 940 kernels->numStamps = -1; 841 941 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."); 942 psTrace("psModules.imcombine", 1, "Number of good stamps: %d\n", match->nGood); 943 944 // the chisq & flux vectors are calculated by pmSubtractionCalculateChisqAndMoments 945 946 // use 3hi/3lo sigma clipping on the chisq fit 947 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV); 948 stats->clipSigma = 5.0; 949 stats->clipIter = 2; 950 psPolynomial1D *model = psPolynomial1DAlloc (PS_POLYNOMIAL_ORD, 2); 951 952 bool result = psVectorClipFitPolynomial1D(model, stats, match->stampMask, 0xff, match->chisq, NULL, match->fluxes); 953 if (!result) { 954 psError(PM_ERR_DATA, false, "Unable to measure statistics for deviations."); 955 psFree(model); 865 956 psFree(stats); 866 psFree(mask); 867 return -1; 868 } 869 psFree(mask); 870 871 // XXX raise an error? 957 return -1; 958 } 872 959 if (isnan(stats->sampleMean)) { 960 psError(PM_ERR_DATA, false, "Unable to measure statistics for deviations."); 961 psFree(model); 873 962 psFree(stats); 874 963 return -1; 875 964 } 876 965 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 966 kernels->mean = stats->sampleMean; 967 kernels->rms = stats->sampleStdev; 968 kernels->numStamps = stats->clippedNvalues; 969 970 psLogMsg ("pmPSFtry", 4, "chisq vs flux fit: %f +/- %f\n", stats->sampleMean, stats->sampleStdev); 971 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Mean deviation from %d stamps: %lf +/- %lf", kernels->numStamps, kernels->mean, kernels->rms); 905 972 906 973 psString ds9name = NULL; // Filename for ds9 region file … … 914 981 int numRejected = 0; // Number of stamps rejected 915 982 int numGood = 0; // Number of good stamps 916 double newMean = 0.0; // New mean917 983 psString log = NULL; // Log message 918 psStringAppend(&log, "Rejecting stamps, mean = %f, threshold = %f\n", mean, limit); 984 985 // save DS9 region files for the stamps and mark for rejection and replacement 919 986 for (int i = 0; i < stamps->num; i++) { 920 987 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 921 if (stamp->status == PM_SUBTRACTION_STAMP_USED) { 988 if (stamp->status != PM_SUBTRACTION_STAMP_USED) { continue; } 989 if (match->stampMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) { 922 990 // Should we reject stars with low deviation? Well, if this is really a Gaussian-like 923 991 // distribution and they're low, then we have the right to ask why. Isn't it suspicious that … … 926 994 // subtract well, in which case very few (if any) stars will be legitimately rejected for being 927 995 // 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; 996 psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d)\n", i, 997 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 998 psStringAppend(&log, "Stamp %d (%d,%d): %f : %f : %f\n", 999 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), 1000 match->chisq->data.F32[i], match->fluxes->data.F32[i], match->chisq->data.F32[i] - psPolynomial1DEval(model, match->fluxes->data.F32[i])); 1001 numRejected++; 1002 for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) { 1003 for (int x = stamp->x - footprint; x <= stamp->x + footprint; x++) { 1004 subMask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= PM_SUBTRACTION_MASK_REJ; 1005 } 1006 } 1007 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "red"); 1008 1009 // Set stamp for replacement 1010 stamp->x = 0; 1011 stamp->y = 0; 1012 stamp->xNorm = NAN; 1013 stamp->yNorm = NAN; 1014 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 1015 // Recalculate convolutions 1016 psFree(stamp->convolutions1); 1017 psFree(stamp->convolutions2); 1018 stamp->convolutions1 = stamp->convolutions2 = NULL; 1019 psFree(stamp->image1); 1020 psFree(stamp->image2); 1021 psFree(stamp->weight); 1022 stamp->image1 = stamp->image2 = stamp->weight = NULL; 1023 psFree(stamp->matrix); 1024 stamp->matrix = NULL; 1025 psFree(stamp->vector); 1026 stamp->vector = NULL; 1027 } else { 1028 numGood++; 1029 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green"); 1030 } 1031 } 969 1032 970 1033 if (numRejected == 0) { … … 978 1041 } 979 1042 1043 psFree(model); 1044 psFree(stats); 1045 980 1046 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); 1047 psLogMsg("psModules.imcombine", PS_LOG_INFO, "%d good stamps; %d rejected.\n", numGood, numRejected); 984 1048 } else { 985 psLogMsg("psModules.imcombine", PS_LOG_INFO, 986 "%d good stamps; 0 rejected.\nMean deviation: %lf\n", 987 numGood, mean); 1049 psLogMsg("psModules.imcombine", PS_LOG_INFO, "%d good stamps; 0 rejected.\n", numGood); 988 1050 } 989 1051 … … 1479 1541 return true; 1480 1542 } 1543 1544 static void pmSubtractionQualityFree(pmSubtractionQuality *quality) { 1545 1546 psFree (quality->fluxes); 1547 psFree (quality->chisq); 1548 psFree (quality->moments); 1549 psFree (quality->stampMask); 1550 } 1551 1552 pmSubtractionQuality *pmSubtractionQualityAlloc() { 1553 1554 pmSubtractionQuality *quality = psAlloc(sizeof(pmSubtractionQuality)); // Stamp list to return 1555 psMemSetDeallocator(quality, (psFreeFunc)pmSubtractionQualityFree); 1556 1557 quality->fluxes = NULL; 1558 quality->chisq = NULL; 1559 quality->moments = NULL; 1560 quality->stampMask = NULL; 1561 1562 quality->score = NAN; 1563 quality->mode = PM_SUBTRACTION_MODE_ERR; 1564 quality->spatialOrder = -1; 1565 quality->nGood = 0; 1566 1567 return quality; 1568 }
Note:
See TracChangeset
for help on using the changeset viewer.
