IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:41:49 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/tap_branches
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/tap_branches

  • branches/tap_branches/psModules

  • branches/tap_branches/psModules/src/imcombine/pmSubtractionStamps.c

    r25120 r27838  
    4646    psFree(list->y);
    4747    psFree(list->flux);
     48    psFree(list->window);
    4849}
    4950
     
    5455    psFree(stamp->image1);
    5556    psFree(stamp->image2);
    56     psFree(stamp->variance);
     57    psFree(stamp->weight);
    5758    psFree(stamp->convolutions1);
    5859    psFree(stamp->convolutions2);
    59 
    60     psFree(stamp->matrix1);
    61     psFree(stamp->matrix2);
    62     psFree(stamp->matrixX);
    63     psFree(stamp->vector1);
    64     psFree(stamp->vector2);
    65 
     60    psFree(stamp->matrix);
     61    psFree(stamp->vector);
    6662}
    6763
     
    8076
    8177// Search a region for a suitable stamp
    82 bool stampSearch(int *xStamp, int *yStamp, // Coordinates of stamp, to return
     78bool stampSearch(float *xStamp, float *yStamp, // Coordinates of stamp, to return
    8379                 float *fluxStamp, // Flux of stamp, to return
    8480                 const psImage *image1, const psImage *image2, // Images to search
     
    9389    *fluxStamp = -INFINITY;             // Flux of best stamp
    9490
     91    // fprintf (stderr, "xMin, xMax: %d, %d -> ", xMin, xMax);
     92
    9593    // Ensure we're not going to go outside the bounds of the image
    9694    xMin = PS_MAX(border, xMin);
     
    9997    yMax = PS_MIN(numRows - border - 1, yMax);
    10098
     99    if (xMax < xMin) return false;
     100    if (yMax < yMin) return false;
     101
     102    psAssert (xMin <= xMax, "x mismatch?");
     103    psAssert (yMin <= yMax, "y mismatch?");
     104
    101105    for (int y = yMin; y <= yMax; y++) {
    102106        for (int x = xMin; x <= xMax; x++) {
     
    115119                ((image1) ? image1->data.F32[y][x] : image2->data.F32[y][x]); // Flux at pixel
    116120            if (flux > *fluxStamp) {
    117                 *xStamp = x;
    118                 *yStamp = y;
     121                *xStamp = x + 0.5;
     122                *yStamp = y + 0.5;
    119123                *fluxStamp = flux;
    120124                found = true;
     
    180184
    181185pmSubtractionStampList *pmSubtractionStampListAlloc(int numCols, int numRows, const psRegion *region,
    182                                                     int footprint, float spacing)
     186                                                    int footprint, float spacing, float normFrac,
     187                                                    float sysErr, float skyErr)
    183188{
    184189    pmSubtractionStampList *list = psAlloc(sizeof(pmSubtractionStampList)); // Stamp list to return
     
    220225    list->y = NULL;
    221226    list->flux = NULL;
     227    list->window = NULL;
     228    list->normFrac = normFrac;
     229    list->normWindow = 0;
    222230    list->footprint = footprint;
     231    list->sysErr = sysErr;
     232    list->skyErr = skyErr;
    223233
    224234    return list;
     
    238248    out->y = NULL;
    239249    out->flux = NULL;
     250    out->window = psMemIncrRefCounter(in->window);
    240251    out->footprint = in->footprint;
     252    out->normWindow = in->normWindow;
    241253
    242254    for (int i = 0; i < num; i++) {
     
    256268        outStamp->image1 = inStamp->image1 ? psKernelCopy(inStamp->image1) : NULL;
    257269        outStamp->image2 = inStamp->image2 ? psKernelCopy(inStamp->image2) : NULL;
    258         outStamp->variance = inStamp->variance ? psKernelCopy(inStamp->variance) : NULL;
     270        outStamp->weight = inStamp->weight ? psKernelCopy(inStamp->weight) : NULL;
    259271
    260272        if (inStamp->convolutions1) {
     
    279291        }
    280292
    281         outStamp->matrix1 = inStamp->matrix1 ? psImageCopy(NULL, inStamp->matrix1, PS_TYPE_F64) : NULL;
    282         outStamp->matrix2 = inStamp->matrix2 ? psImageCopy(NULL, inStamp->matrix2, PS_TYPE_F64) : NULL;
    283         outStamp->matrixX = inStamp->matrixX ? psImageCopy(NULL, inStamp->matrixX, PS_TYPE_F64) : NULL;
    284         outStamp->vector1 = inStamp->vector1 ? psVectorCopy(NULL, inStamp->vector1, PS_TYPE_F64) : NULL;
    285         outStamp->vector2 = inStamp->vector2 ? psVectorCopy(NULL, inStamp->vector2, PS_TYPE_F64) : NULL;
     293        outStamp->matrix = inStamp->matrix ? psImageCopy(NULL, inStamp->matrix, PS_TYPE_F64) : NULL;
     294        outStamp->vector = inStamp->vector ? psVectorCopy(NULL, inStamp->vector, PS_TYPE_F64) : NULL;
    286295
    287296        out->stamps->data[i] = outStamp;
     
    305314    stamp->image1 = NULL;
    306315    stamp->image2 = NULL;
    307     stamp->variance = NULL;
     316    stamp->weight = NULL;
    308317    stamp->convolutions1 = NULL;
    309318    stamp->convolutions2 = NULL;
    310319
    311     stamp->matrix1 = NULL;
    312     stamp->matrix2 = NULL;
    313     stamp->matrixX = NULL;
    314     stamp->vector1 = NULL;
    315     stamp->vector2 = NULL;
     320    stamp->matrix = NULL;
     321    stamp->vector = NULL;
     322    stamp->norm = NAN;
    316323
    317324    return stamp;
     
    322329                                                const psImage *image2, const psImage *subMask,
    323330                                                const psRegion *region, float thresh1, float thresh2,
    324                                                 int size, int footprint, float spacing,
    325                                                 pmSubtractionMode mode)
     331                                                int size, int footprint, float spacing, float normFrac,
     332                                                float sysErr, float skyErr, pmSubtractionMode mode)
    326333{
    327334    if (!image1 && !image2) {
     
    362369        if (psRegionIsNaN(*region)) {
    363370            psString string = psRegionToString(*region);
    364             psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Input region (%s) contains NAN values", string);
     371            psError(PM_ERR_PROG, true, "Input region (%s) contains NAN values", string);
    365372            psFree(string);
    366373            return false;
     
    369376            region->y0 < 0 || region->y1 > numRows) {
    370377            psString string = psRegionToString(*region);
    371             psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Input region (%s) does not fit in image (%dx%d)",
     378            psError(PM_ERR_PROG, true, "Input region (%s) does not fit in image (%dx%d)",
    372379                    string, numCols, numRows);
    373380            psFree(string);
     
    379386
    380387    if (!stamps) {
    381         stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing);
     388        stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing,
     389                                             normFrac, sysErr, skyErr);
    382390    }
    383391
     
    401409            numSearch++;
    402410
    403             int xStamp = 0, yStamp = 0; // Coordinates of stamp
     411            float xStamp = 0.0, yStamp = 0.0; // Coordinates of stamp
    404412            float fluxStamp = -INFINITY; // Flux of stamp
    405413            bool goodStamp = false;     // Found a good stamp?
     
    413421                // Take stamps off the top of the (sorted) list
    414422                for (int j = xList->n - 1; j >= 0 && !goodStamp; j--) {
    415                     int xCentre = xList->data.F32[j] + 0.5, yCentre = yList->data.F32[j] + 0.5;// Stamp centre
    416 
    417423                    // Chop off the top of the list
    418424                    xList->n = j;
     
    420426                    fluxList->n = j;
    421427
     428#if 0
    422429                    // Fish around a bit to see if we can find a pixel that isn't masked
     430                    // This is not a good idea if we're using the window feature
    423431                    psTrace("psModules.imcombine", 7, "Searching for stamp %d around %d,%d\n",
    424432                            i, xCentre, yCentre);
    425433
    426434                    // Search bounds
     435                    int xCentre = xList->data.F32[j] - 0.5, yCentre = yList->data.F32[j] - 0.5;// Stamp centre
    427436                    int search = footprint - size; // Search radius
    428437                    int xMin = PS_MAX(border, xCentre - search);
     
    433442                    goodStamp = stampSearch(&xStamp, &yStamp, &fluxStamp, image1, image2, thresh1, thresh2,
    434443                                            subMask, xMin, xMax, yMin, yMax, numCols, numRows, border);
     444                    // fprintf (stderr, "find: %d %d ==> %5.1f %5.1f (\n", xCentre, yCentre, xStamp, yStamp);
     445#else
     446                    // Only search the exact centre pixel
     447                    goodStamp = stampSearch(&xStamp, &yStamp, &fluxStamp, image1, image2, thresh1, thresh2,
     448                                            subMask, xList->data.F32[j], xList->data.F32[j],
     449                                            yList->data.F32[j], yList->data.F32[j], numCols, numRows, border);
     450#endif
     451                    if (0 && goodStamp) {
     452                        fprintf (stderr, "find: %6.1f < %6.1f < %6.1f, %6.1f < %6.1f %6.1f\n",
     453                                 region->x0 + size, xStamp, region->x1 - size,
     454                                 region->y0 + size, yStamp, region->y1 - size);
     455                    }
    435456                }
    436457            } else {
     
    452473                psFree(stamp->image1);
    453474                psFree(stamp->image2);
    454                 psFree(stamp->variance);
     475                psFree(stamp->weight);
    455476                psFree(stamp->convolutions1);
    456477                psFree(stamp->convolutions2);
    457                 stamp->image1 = stamp->image2 = stamp->variance = NULL;
     478                stamp->image1 = stamp->image2 = stamp->weight = NULL;
    458479                stamp->convolutions1 = stamp->convolutions2 = NULL;
    459480
     
    487508                                               const psImage *image, const psImage *subMask,
    488509                                               const psRegion *region, int size, int footprint,
    489                                                float spacing, pmSubtractionMode mode)
     510                                               float spacing, float normFrac, float sysErr, float skyErr,
     511                                               pmSubtractionMode mode)
    490512
    491513{
     
    507529    int numStars = x->n;                // Number of stars
    508530    pmSubtractionStampList *stamps = pmSubtractionStampListAlloc(subMask->numCols, subMask->numRows,
    509                                                                  region, footprint, spacing); // Stamp list
     531                                                                 region, footprint, spacing,
     532                                                                 normFrac, sysErr, skyErr); // Stamp list
    510533    int numStamps = stamps->num;        // Number of stamps
    511534
     
    514537    psStringAppend(&ds9name, "stamps_all_%d.ds9", ds9num);
    515538    FILE *ds9 = pmSubtractionStampsFile(stamps, ds9name, "all stamps"); // ds9 region file
     539    psFree(ds9name);
    516540    ds9num++;
    517541
     
    529553    for (int i = 0; i < numStars; i++) {
    530554        float xStamp = x->data.F32[i], yStamp = y->data.F32[i]; // Coordinates of stamp
    531         int xPix = xStamp + 0.5, yPix = yStamp + 0.5; // Pixel coordinate of stamp
     555        int xPix = xStamp - 0.5, yPix = yStamp - 0.5; // Pixel coordinate of stamp
    532556        if (!checkStampRegion(xPix, yPix, region)) {
    533557            // It's not in the big region
     
    537561            continue;
    538562        }
     563
     564        // fprintf (stderr, "stamp: %5.1f %5.1f == %d %d\n", xStamp, yStamp, xPix, yPix);
    539565
    540566        bool found = false;
     
    605631
    606632
     633bool pmSubtractionStampsGetWindow(pmSubtractionStampList *stamps, int kernelSize)
     634{
     635    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
     636    PS_ASSERT_INT_NONNEGATIVE(kernelSize, false);
     637
     638    int size = stamps->footprint; // Size of postage stamps
     639
     640    psFree (stamps->window);
     641    stamps->window = psKernelAlloc(-size, size, -size, size);
     642    psImageInit(stamps->window->image, 0.0);
     643
     644    // generate normalizations for each stamp
     645    psVector *norm1 = psVectorAlloc(stamps->num, PS_TYPE_F32);
     646    psVector *norm2 = psVectorAlloc(stamps->num, PS_TYPE_F32);
     647    for (int i = 0; i < stamps->num; i++) {
     648        pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
     649        if (!stamp) continue;
     650        if (!stamp->image1) continue;
     651        if (!stamp->image2) continue;
     652
     653        float sum1 = 0.0;
     654        float sum2 = 0.0;
     655        for (int y = -size; y <= size; y++) {
     656            for (int x = -size; x <= size; x++) {
     657                sum1 += stamp->image1->kernel[y][x];
     658                sum2 += stamp->image2->kernel[y][x];
     659            }
     660        }
     661        norm1->data.F32[i] = sum1;
     662        norm2->data.F32[i] = sum2;
     663    }
     664
     665    // storage vector for flux data
     666    psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
     667    psVector *flux1 = psVectorAllocEmpty(2*stamps->num, PS_TYPE_F32);
     668    psVector *flux2 = psVectorAllocEmpty(2*stamps->num, PS_TYPE_F32);
     669
     670    // generate the window pixels
     671    double sum = 0.0;                   // Sum inside the window
     672    float maxValue = 0.0;               // Maximum value, for normalisation
     673    for (int y = -size; y <= size; y++) {
     674        for (int x = -size; x <= size; x++) {
     675
     676            flux1->n = 0;
     677            flux2->n = 0;
     678            for (int i = 0; i < stamps->num; i++) {
     679                pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
     680                if (!stamp) continue;
     681                if (!stamp->image1) continue;
     682                if (!stamp->image2) continue;
     683
     684                psVectorAppend(flux1, stamp->image1->kernel[y][x] / norm1->data.F32[i]);
     685                psVectorAppend(flux2, stamp->image2->kernel[y][x] / norm2->data.F32[i]);
     686            }
     687
     688            psStatsInit (stats);
     689            if (!psVectorStats (stats, flux1, NULL, NULL, 0)) {
     690                psAbort ("failed to generate stats");
     691            }
     692            float f1 = stats->robustMedian;
     693            psStatsInit (stats);
     694            if (!psVectorStats (stats, flux2, NULL, NULL, 0)) {
     695                psAbort ("failed to generate stats");
     696            }
     697            float f2 = stats->robustMedian;
     698
     699            stamps->window->kernel[y][x] = f1 + f2;
     700            if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(size)) {
     701                sum += stamps->window->kernel[y][x];
     702            }
     703            maxValue = PS_MAX(maxValue, stamps->window->kernel[y][x]);
     704        }
     705    }
     706
     707    psTrace("psModules.imcombine", 3, "Window total: %f, threshold: %f\n",
     708            sum, (1.0 - stamps->normFrac) * sum);
     709    bool done = false;
     710    for (int radius = 1; radius <= size && !done; radius++) {
     711        double within = 0.0;
     712        for (int y = -radius; y <= radius; y++) {
     713            for (int x = -radius; x <= radius; x++) {
     714                if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) {
     715                    within += stamps->window->kernel[y][x];
     716                }
     717            }
     718        }
     719        psTrace("psModules.imcombine", 5, "Radius %d: %f\n", radius, within);
     720        if (within > (1.0 - stamps->normFrac) * sum) {
     721            stamps->normWindow = radius;
     722            done = true;
     723        }
     724    }
     725
     726    psTrace("psModules.imcombine", 3, "Normalisation window radius set to %d\n", stamps->normWindow);
     727    if (stamps->normWindow == 0 || stamps->normWindow >= size) {
     728        psError(PM_ERR_STAMPS, true, "Unable to determine normalisation window size.");
     729        return false;
     730    }
     731
     732    // re-normalize so chisquare values are sensible
     733    for (int y = -size; y <= size; y++) {
     734        for (int x = -size; x <= size; x++) {
     735            stamps->window->kernel[y][x] /= maxValue;
     736        }
     737    }
     738
     739#if 0
     740    {
     741        psFits *fits = psFitsOpen ("window.fits", "w");
     742        psFitsWriteImage (fits, NULL, stamps->window->image, 0, NULL);
     743        psFitsClose (fits);
     744    }
     745#endif
     746
     747    psFree (stats);
     748    psFree (flux1);
     749    psFree(flux2);
     750    psFree (norm1);
     751    psFree (norm2);
     752    return true;
     753}
     754
    607755bool pmSubtractionStampsExtract(pmSubtractionStampList *stamps, psImage *image1, psImage *image2,
    608                                 psImage *variance, int kernelSize)
     756                                psImage *variance, int kernelSize, psRegion bounds)
    609757{
    610758    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
     
    616764        PS_ASSERT_IMAGE_TYPE(image2, PS_TYPE_F32, false);
    617765    }
    618     PS_ASSERT_IMAGE_NON_NULL(variance, false);
    619     PS_ASSERT_IMAGES_SIZE_EQUAL(variance, image1, false);
    620     PS_ASSERT_IMAGE_TYPE(variance, PS_TYPE_F32, false);
    621     PS_ASSERT_INT_NONNEGATIVE(kernelSize, false);
    622 
    623     int numCols = image1->numCols, numRows = image1->numRows; // Size of images
     766    if (variance) {
     767        PS_ASSERT_IMAGE_NON_NULL(variance, false);
     768        PS_ASSERT_IMAGES_SIZE_EQUAL(variance, image1, false);
     769        PS_ASSERT_IMAGE_TYPE(variance, PS_TYPE_F32, false);
     770        PS_ASSERT_INT_NONNEGATIVE(kernelSize, false);
     771    }
     772
    624773    int size = kernelSize + stamps->footprint; // Size of postage stamps
    625774
     
    630779        }
    631780
    632         if (isnan(stamp->xNorm)) {
    633             stamp->xNorm = 2.0 * (stamp->x - (float)numCols/2.0) / (float)numCols;
    634         }
    635         if (isnan(stamp->yNorm)) {
    636             stamp->yNorm = 2.0 * (stamp->y - (float)numRows/2.0) / (float)numRows;
    637         }
    638 
    639         int x = stamp->x + 0.5, y = stamp->y + 0.5; // Stamp coordinates
    640         if (x < size || x > numCols - size || y < size || y > numRows - size) {
    641             psError(PS_ERR_UNKNOWN, false, "Stamp %d (%d,%d) is within the image border.\n", i, x, y);
     781        p_pmSubtractionPolynomialNormCoords(&stamp->xNorm, &stamp->yNorm, stamp->x, stamp->y,
     782                                            bounds.x0, bounds.x1, bounds.y0, bounds.y1);
     783
     784        int x = stamp->x - 0.5, y = stamp->y - 0.5; // Stamp coordinates
     785        // fprintf (stderr, "stamp: %5.1f %5.1f == %d %d (size: %d)\n", stamp->x, stamp->y, x, y, size);
     786
     787        if (x < bounds.x0 + size || x > bounds.x1 - size || y < bounds.y0 + size || y > bounds.y1 - size) {
     788            psError(PM_ERR_PROG, false, "Stamp %d (%d,%d) is within the region border.\n", i, x, y);
    642789            return false;
    643790        }
     
    646793        assert(stamp->image1 == NULL);
    647794        assert(stamp->image2 == NULL);
    648         assert(stamp->variance == NULL);
     795        assert(stamp->weight == NULL);
    649796
    650797        psRegion region = psRegionSet(x - size, x + size + 1, y - size, y + size + 1); // Region of interest
     
    660807        }
    661808
    662         psImage *wtSub = psImageSubset(variance, region); // Subimage with stamp
    663         stamp->variance = psKernelAllocFromImage(wtSub, size, size);
    664         psFree(wtSub);                  // Drop reference
     809        psKernel *weight = stamp->weight = psKernelAlloc(-size, size, -size, size); // Weight = 1/variance
     810        if (variance) {
     811            psImage *varSub = psImageSubset(variance, region); // Subimage with stamp
     812            psKernel *var = psKernelAllocFromImage(varSub, size, size); // Variance postage stamp
     813
     814            if ((isfinite(stamps->skyErr) && (stamps->skyErr > 0)) ||
     815                (isfinite(stamps->sysErr) && (stamps->sysErr > 0))) {
     816                float sysErr = 0.25 * PS_SQR(stamps->sysErr); // Systematic error
     817                float skyErr = stamps->skyErr;
     818                psKernel *image1 = stamp->image1, *image2 = stamp->image2; // Input images
     819                for (int y = -size; y <= size; y++) {
     820                    for (int x = -size; x <= size; x++) {
     821                        float additional = image1->kernel[y][x] + image2->kernel[y][x];
     822                        weight->kernel[y][x] = 1.0 / (skyErr + var->kernel[y][x] + sysErr * PS_SQR(additional));
     823                    }
     824                }
     825            } else {
     826                for (int y = -size; y <= size; y++) {
     827                    for (int x = -size; x <= size; x++) {
     828                        weight->kernel[y][x] = 1.0 / var->kernel[y][x];
     829                    }
     830                }
     831            }
     832            psFree(var);
     833            psFree(varSub);
     834        } else {
     835            psImageInit(weight->image, 1.0);
     836        }
    665837
    666838        stamp->status = PM_SUBTRACTION_STAMP_CALCULATE;
     
    673845                                                          const psImage *subMask, const psRegion *region,
    674846                                                          int size, int footprint, float spacing,
     847                                                          float normFrac, float sysErr, float skyErr,
    675848                                                          pmSubtractionMode mode)
    676849{
     
    696869            y->data.F32[numOut] = source->peak->yf;
    697870        }
     871        // fprintf (stderr, "stamp: %5.1f %5.1f\n", x->data.F32[numOut], y->data.F32[numOut]);
    698872        numOut++;
    699873    }
     
    702876
    703877    pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, image, subMask, region, size,
    704                                                             footprint, spacing, mode); // Stamps to return
     878                                                            footprint, spacing, normFrac,
     879                                                            sysErr, skyErr, mode); // Stamps
    705880    psFree(x);
    706881    psFree(y);
    707882
    708883    if (!stamps) {
    709         psError(PS_ERR_UNKNOWN, false, "Unable to set stamps from sources.");
     884        psError(psErrorCodeLast(), false, "Unable to set stamps from sources.");
    710885    }
    711886
     
    716891pmSubtractionStampList *pmSubtractionStampsSetFromFile(const char *filename, const psImage *image,
    717892                                                       const psImage *subMask, const psRegion *region,
    718                                                        int size, int footprint, float spacing,
    719                                                        pmSubtractionMode mode)
     893                                                       int size, int footprint, float spacing, float normFrac,
     894                                                       float sysErr, float skyErr, pmSubtractionMode mode)
    720895{
    721896    PS_ASSERT_STRING_NON_EMPTY(filename, NULL);
     
    724899    psArray *data = psVectorsReadFromFile(filename, "%f %f");
    725900    if (!data) {
    726         psError(PS_ERR_IO, false, "Unable to read stamps file %s", filename);
     901        psError(psErrorCodeLast(), false, "Unable to read stamps file %s", filename);
    727902        return NULL;
    728903    }
     
    734909
    735910    pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, image, subMask, region, size, footprint,
    736                                                             spacing, mode);
     911                                                            spacing, normFrac, sysErr, skyErr, mode);
    737912    psFree(data);
    738913
     
    740915
    741916}
     917
     918
     919bool pmSubtractionStampsResetStatus (pmSubtractionStampList *stamps) {
     920
     921    for (int i = 0; i < stamps->num; i++) {
     922        pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
     923        if (!stamp) continue;
     924        if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue;
     925        stamp->status = PM_SUBTRACTION_STAMP_CALCULATE;
     926    }
     927    return true;
     928}
     929
Note: See TracChangeset for help on using the changeset viewer.