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:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/tap_branches

  • branches/tap_branches/psphot

  • branches/tap_branches/psphot/src

    • Property svn:ignore
      •  

        old new  
        1919psphotMomentsStudy
        2020psphotPetrosianStudy
         21psphotForced
         22psphotMakePSF
         23psphotStack
  • branches/tap_branches/psphot/src/psphotSourceStats.c

    r25852 r27838  
    11# include "psphotInternal.h"
    22
    3 bool psphotSetMomentsWindow (psMetadata *recipe, psMetadata *analysis, psArray *sources);
    4 
    5 psArray *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections, bool setWindow) {
     3// convert detections to sources and measure their basic properties (moments, local sky, sky
     4// variance) Note: this function only generates sources for the new peaks (peak->assigned).
     5// The new sources are added to any existing sources on detections->newSources.  The sources
     6// on detections->allSources are ignored.
     7bool psphotSourceStats (pmConfig *config, const pmFPAview *view, bool setWindow)
     8{
     9    bool status = true;
     10
     11    // select the appropriate recipe information
     12    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     13    psAssert (recipe, "missing recipe?");
     14
     15    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     16    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     17
     18    // loop over the available readouts
     19    for (int i = 0; i < num; i++) {
     20        if (!psphotSourceStatsReadout (config, view, "PSPHOT.INPUT", i, recipe, setWindow)) {
     21            psError (PSPHOT_ERR_CONFIG, false, "failed to find initial detections for PSPHOT.INPUT entry %d", i);
     22            return false;
     23        }
     24    }
     25    return true;
     26}
     27
     28bool psphotSourceStatsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool setWindow) {
    629
    730    bool status = false;
     
    1033    psTimerStart ("psphot.stats");
    1134
    12     // select the appropriate recipe information
    13     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    14     assert (recipe);
     35    // find the currently selected readout
     36    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     37    psAssert (file, "missing file?");
     38
     39    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     40    psAssert (readout, "missing readout?");
     41
     42    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     43    psAssert (detections, "missing detections?");
     44
     45    // XXX TEST:
     46    if (detections->allSources) {
     47        psphotMaskCosmicRayFootprintCheck(detections->allSources);
     48    }
     49    if (detections->newSources) {
     50        psphotMaskCosmicRayFootprintCheck(detections->newSources);
     51    }
    1552
    1653    // determine the number of allowed threads
     
    2158
    2259    // determine properties (sky, moments) of initial sources
    23     float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
    24     if (!status) return NULL;
    25 
     60    float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
     61    psAssert (status, "missing SKY_OUTER_RADIUS in recipe?");
     62
     63    // XXX this seems like an arbitrary number...
    2664    OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
    2765
    2866    char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
    29     if (!status) return NULL;
     67    psAssert (status, "missing BREAK_POINT?");
     68
     69    float INNER        = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS"); psAssert (status, "missing SKY_INNER_RADIUS");
     70    float MIN_SN       = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); psAssert (status, "missing MOMENTS_SN_MIN");
     71
     72    // bit-masks to test for good/bad pixels
     73    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
     74    psAssert (maskVal, "missing MASK.PSPHOT");
     75
     76    // bit-mask to mark pixels not used in analysis
     77    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
     78    psAssert (markVal, "missing MARK.PSPHOT");
    3079
    3180    psArray *peaks = detections->peaks;
    3281    if (!peaks) {
    3382        psError(PS_ERR_UNEXPECTED_NULL, false, "No peaks found!");
    34         return NULL;
     83        return false;
    3584    }
    3685
    3786    // generate the array of sources, define the associated pixel
    38     sources = psArrayAllocEmpty (peaks->n);
     87    if (!detections->newSources) {
     88        detections->newSources = psArrayAllocEmpty (peaks->n);
     89    }
     90    sources = detections->newSources;
     91
     92    // if there are no peaks, we save the empty source array and return
     93    if (!peaks->n) {
     94        return true;
     95    }
    3996
    4097    for (int i = 0; i < peaks->n; i++) {
     
    45102        // create a new source
    46103        pmSource *source = pmSourceAlloc();
     104        source->imageID = index;
    47105
    48106        // add the peak
     
    58116        psArrayAdd (sources, 100, source);
    59117        psFree (source);
     118    }
     119
     120    if (!strcasecmp (breakPt, "PEAKS")) {
     121        psLogMsg ("psphot", PS_LOG_INFO, "%ld sources : %f sec\n", sources->n, psTimerMark ("psphot.stats"));
     122        psLogMsg ("psphot", PS_LOG_INFO, "break point PEAKS, skipping MOMENTS\n");
     123        psphotVisualShowMoments (sources);
     124        return true;
     125    }
     126
     127    if (setWindow) {
     128        if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
     129            psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
     130            psFree(detections->newSources);
     131            return false;
     132        }
     133    }
     134
     135    // if we have measured the window, we will be saving the modified version of these recipe values on readout->analysis
     136    float SIGMA = psMetadataLookupF32 (&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
     137    if (!status) {
     138        SIGMA = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
     139    }
     140    float RADIUS = psMetadataLookupF32 (&status, readout->analysis, "PSF_MOMENTS_RADIUS");
     141    if (!status) {
     142        RADIUS = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
     143    }
     144
     145    // threaded measurement of the source magnitudes
     146    int Nfail = 0;
     147    int Nmoments = 0;
     148    int Nfaint = 0;
     149
     150    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
     151    int Cx = 1, Cy = 1;
     152    psphotChooseCellSizes (&Cx, &Cy, readout, nThreads);
     153
     154    psArray *cellGroups = psphotAssignSources (Cx, Cy, sources);
     155
     156    for (int i = 0; i < cellGroups->n; i++) {
     157
     158        psArray *cells = cellGroups->data[i];
     159
     160        for (int j = 0; j < cells->n; j++) {
     161
     162            // allocate a job -- if threads are not defined, this just runs the job
     163            psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS");
     164
     165            psArrayAdd(job->args, 1, cells->data[j]); // sources
     166
     167            PS_ARRAY_ADD_SCALAR(job->args, INNER,   PS_TYPE_F32);
     168            PS_ARRAY_ADD_SCALAR(job->args, MIN_SN,  PS_TYPE_F32);
     169            PS_ARRAY_ADD_SCALAR(job->args, RADIUS,  PS_TYPE_F32);
     170            PS_ARRAY_ADD_SCALAR(job->args, SIGMA,   PS_TYPE_F32);
     171
     172            PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK);
     173            PS_ARRAY_ADD_SCALAR(job->args, markVal, PS_TYPE_IMAGE_MASK);
     174
     175            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nmoments
     176            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfail
     177            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfaint
     178
     179            if (!psThreadJobAddPending(job)) {
     180                psError(PS_ERR_UNKNOWN, false, "Unable to launch thread job PSPHOT_SOURCE_STATS");
     181                psFree (job);
     182                psFree(detections->newSources);
     183                return false;
     184            }
     185            psFree(job);
     186        }
     187
     188        // wait for the threads to finish and manage results
     189        if (!psThreadPoolWait (false)) {
     190            psError(PS_ERR_UNKNOWN, false, "Failure in thread job PSPHOT_SOURCE_STATS");
     191            psFree(detections->newSources);
     192            return false;
     193        }
     194
     195        // we have only supplied one type of job, so we can assume the types here
     196        psThreadJob *job = NULL;
     197        while ((job = psThreadJobGetDone()) != NULL) {
     198            if (job->args->n < 1) {
     199                fprintf (stderr, "error with job\n");
     200            } else {
     201                psScalar *scalar = NULL;
     202                scalar = job->args->data[7];
     203                Nmoments += scalar->data.S32;
     204                scalar = job->args->data[8];
     205                Nfail += scalar->data.S32;
     206                scalar = job->args->data[9];
     207                Nfaint += scalar->data.S32;
     208            }
     209            psFree(job);
     210        }
     211    }
     212
     213    psFree (cellGroups);
     214
     215    psLogMsg ("psphot", PS_LOG_INFO, "%ld sources, %d moments, %d faint, %d failed: %f sec\n", sources->n, Nmoments, Nfaint, Nfail, psTimerMark ("psphot.stats"));
     216
     217    psphotVisualShowMoments (sources);
     218
     219    if (detections->allSources) {
     220        psphotMaskCosmicRayFootprintCheck(detections->allSources);
     221    }
     222    if (detections->newSources) {
     223        psphotMaskCosmicRayFootprintCheck(detections->newSources);
     224    }
     225
     226    return true;
     227}
     228
     229// this function is currently only called by psphotCheckExtSources
     230bool psphotSourceStatsUpdate (psArray *sources, pmConfig *config, pmReadout *readout) {
     231
     232    bool status = false;
     233
     234    psTimerStart ("psphot.stats");
     235
     236    // select the appropriate recipe information
     237    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     238    assert (recipe);
     239
     240    // determine the number of allowed threads
     241    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
     242    if (!status) {
     243        nThreads = 0;
     244    }
     245
     246    // determine properties (sky, moments) of initial sources
     247    float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
     248    if (!status) return false;
     249
     250    OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
     251
     252    char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
     253    if (!status) return false;
     254
     255    for (int i = 0; i < sources->n; i++) {
     256
     257        pmSource *source = sources->data[i];
     258        if (!source->peak) continue; // XXX how can we have a peak-less source?
     259
     260        // allocate space for moments
     261        if (!source->moments) {
     262            source->moments = pmMomentsAlloc();
     263        }
     264
     265        // allocate image, weight, mask arrays for each peak (square of radius OUTER)
     266        pmSourceDefinePixels (source, readout, source->peak->x, source->peak->y, OUTER);
     267        source->peak->assigned = true;
    60268    }
    61269
     
    67275    }
    68276
    69     if (setWindow) {
    70         if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
    71             psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
    72             return NULL;
    73         }
     277    // XXX how else could we get the window size in?
     278    if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
     279        psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
     280        return NULL;
    74281    }
    75282
     
    94301            psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS");
    95302
     303            // XXX: this must match the above
    96304            psArrayAdd(job->args, 1, cells->data[j]); // sources
    97305            psArrayAdd(job->args, 1, recipe);
     
    148356
    149357    psArray *sources                = job->args->data[0];
    150     psMetadata *recipe              = job->args->data[1];
    151 
    152     float INNER        = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");
    153     if (!status) return false;
    154     float MIN_SN       = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
    155     if (!status) return false;
    156     float RADIUS       = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
    157     if (!status) return false;
    158     float SIGMA        = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
    159     if (!status) return false;
    160 
    161     // bit-masks to test for good/bad pixels
    162     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
    163     assert (maskVal);
    164 
    165     // bit-mask to mark pixels not used in analysis
    166     psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
    167     assert (markVal);
     358
     359    float INNER                     = PS_SCALAR_VALUE(job->args->data[1],F32);
     360    float MIN_SN                    = PS_SCALAR_VALUE(job->args->data[2],F32);
     361    float RADIUS                    = PS_SCALAR_VALUE(job->args->data[3],F32);
     362    float SIGMA                     = PS_SCALAR_VALUE(job->args->data[4],F32);
     363
     364    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[5],PS_TYPE_IMAGE_MASK_DATA);
     365    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
    168366
    169367    // maskVal is used to test for rejected pixels, and must include markVal
     
    176374    for (int i = 0; i < sources->n; i++) {
    177375        pmSource *source = sources->data[i];
     376
     377        if (source->tmpFlags & PM_SOURCE_TMPF_MOMENTS_MEASURED) continue;
     378        source->tmpFlags |= PM_SOURCE_TMPF_MOMENTS_MEASURED;
    178379
    179380        // skip faint sources for moments measurement
     
    205406
    206407        // measure basic source moments (no S/N clipping on input pixels)
    207         status = pmSourceMoments (source, RADIUS, SIGMA, 0.0);
     408        status = pmSourceMoments (source, RADIUS, SIGMA, 0.0, maskVal);
    208409        if (status) {
    209410            Nmoments ++;
     
    215416        BIG_RADIUS = PS_MIN (INNER, 3*RADIUS);
    216417        psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y);
    217         status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, 0.0);
     418        status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, 0.0, maskVal);
    218419        if (status) {
    219420            source->mode |= PM_SOURCE_MODE_BIG_RADIUS;
     
    229430
    230431    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    231     scalar = job->args->data[2];
     432    scalar = job->args->data[7];
    232433    scalar->data.S32 = Nmoments;
    233434
    234     scalar = job->args->data[3];
     435    scalar = job->args->data[8];
    235436    scalar->data.S32 = Nfail;
    236437
    237     scalar = job->args->data[4];
     438    scalar = job->args->data[9];
    238439    scalar->data.S32 = Nfaint;
    239440
     
    242443
    243444// this function attempts to iteratively determine the best value for sigma of the moments weighting Gaussian
     445// this function modifies the recipe values MOMENTS_SX_MAX, MOMENTS_SY_MAX, and PSF_CLUMP_GRID_SCALE, used by pmSourcePSFClump
    244446bool psphotSetMomentsWindow (psMetadata *recipe, psMetadata *analysis, psArray *sources) {
    245447
    246448    bool status;
    247449
    248     float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
    249     if (!status) return false;
     450    float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); psAssert (status, "missing MOMENTS_SN_MIN");
     451    float PSF_SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM"); psAssert (status, "missing PSF_SN_LIM");
     452    psF32 MOMENTS_AR_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_AR_MAX"); psAssert (status, "missing MOMENTS_AR_MAX");
    250453
    251454    // XXX move this to a config file?
    252     float sigma[4] = {1.0, 2.0, 3.0, 4.5};
    253     float Sout[4];
     455    # define NSIGMA 8
     456    float sigma[NSIGMA] = {1.0, 2.0, 3.0, 4.5, 6.0, 9.0, 12.0, 18.0};
     457    float Sout[NSIGMA];
    254458
    255459    // this sorts by peak->SN
     
    257461
    258462    // loop over radii:
    259     for (int i = 0; i < 4; i++) {
     463    for (int i = 0; i < NSIGMA; i++) {
    260464
    261465        // XXX move max source number to config
     
    272476
    273477            // measure basic source moments (no S/N clipping on input pixels)
    274             status = pmSourceMoments (source, 4*sigma[i], sigma[i], 0.0);
     478            status = pmSourceMoments (source, 4*sigma[i], sigma[i], 0.0, 0xffff);
    275479        }
    276480
    277481        // choose a grid scale that is a fixed fraction of the psf sigma^2
    278         psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(sigma[i]));
    279         psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));
    280         psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));
     482        float PSF_CLUMP_GRID_SCALE = 0.1*PS_SQR(sigma[i]);
     483        float MOMENTS_SX_MAX = 2.0*PS_SQR(sigma[i]);
     484        float MOMENTS_SY_MAX = 2.0*PS_SQR(sigma[i]);
    281485
    282486        // determine the PSF parameters from the source moment values
    283         pmPSFClump psfClump = pmSourcePSFClump (NULL, sources, recipe);
     487        pmPSFClump psfClump = pmSourcePSFClump (NULL, NULL, sources, PSF_SN_LIM, PSF_CLUMP_GRID_SCALE, MOMENTS_SX_MAX, MOMENTS_SY_MAX, MOMENTS_AR_MAX);
    284488        psLogMsg ("psphot", 3, "radius %.1f, nStars: %d, nSigma: %5.2f, X,  Y: %f, %f (%f, %f)\n", sigma[i], psfClump.nStars, psfClump.nSigma, psfClump.X, psfClump.Y, sqrt(psfClump.X) / sigma[i], sqrt(psfClump.Y) / sigma[i]);
    285489
     
    296500        psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
    297501
    298         // psphotVisualPlotMoments (recipe, sources);
     502        psphotVisualPlotMoments (recipe, analysis, sources);
    299503
    300504        Sout[i] = sqrt(0.5*(psfClump.X + psfClump.Y)) / sigma[i];
     
    302506
    303507    // we are looking for sigma for which Sout = 0.65 (or some other value)
    304 
    305508    float Sigma = NAN;
    306509    float minS = Sout[0];
    307510    float maxS = Sout[0];
    308     for (int i = 0; i < 4; i++) {
     511    for (int i = 0; i < NSIGMA; i++) {
    309512        minS = PS_MIN(Sout[i], minS);
    310513        maxS = PS_MAX(Sout[i], maxS);
    311514    }
    312     if (minS > 0.65) Sigma = sigma[3];
     515    if (minS > 0.65) Sigma = sigma[NSIGMA-1];
    313516    if (maxS < 0.65) Sigma = sigma[0];
    314517
    315     for (int i = 0; i < 3; i++) {
     518    for (int i = 0; i < NSIGMA - 1 && isnan(Sigma); i++) {
     519        if (!isfinite(Sout[i]) || !isfinite(Sout[i+1])) continue;
    316520        if ((Sout[i] > 0.65) && (Sout[i+1] > 0.65)) continue;
    317521        if ((Sout[i] < 0.65) && (Sout[i+1] < 0.65)) continue;
     
    321525
    322526    // choose a grid scale that is a fixed fraction of the psf sigma^2
    323     psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(Sigma));
    324     psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
    325     psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
    326     psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_GAUSS_SIGMA", PS_META_REPLACE, "moments limit", Sigma);
    327     psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma);
     527    psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(Sigma));
     528    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
     529    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
     530    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_GAUSS_SIGMA", PS_META_REPLACE, "moments limit", Sigma);
     531    psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma);
    328532
    329533    psLogMsg ("psphot", 3, "using window function with sigma = %f\n", Sigma);
    330534    return true;
    331535}
     536
     537// if we use the footprints, the output peaks list contains both old and new peaks,
     538// otherwise it only contains the new peaks.
     539
Note: See TracChangeset for help on using the changeset viewer.