Changeset 30622 for trunk/psModules/src/imcombine/pmSubtraction.c
- Timestamp:
- Feb 13, 2011, 12:19:53 PM (15 years ago)
- File:
-
- 1 edited
-
trunk/psModules/src/imcombine/pmSubtraction.c (modified) (14 diffs)
Legend:
- Unmodified
- Added
- Removed
-
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 }
Note:
See TracChangeset
for help on using the changeset viewer.
