- Timestamp:
- Feb 5, 2010, 1:38:43 PM (16 years ago)
- Location:
- branches/eam_branches/20091201/psphot
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
src/psphotSourceStats.c (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/20091201/psphot
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/eam_branches/psphot.stack.20100120 merged eligible /branches/eam_branches/20091113/psphot 26119-26255
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
branches/eam_branches/20091201/psphot/src/psphotSourceStats.c
r26596 r26788 1 1 # include "psphotInternal.h" 2 2 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 bool psphotSourceStats (pmConfig *config, const pmFPAview *view, bool setWindow) 6 { 7 bool status = true; 8 9 // select the appropriate recipe information 10 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE); 11 psAssert (recipe, "missing recipe?"); 12 13 int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM"); 14 psAssert (status, "programming error: must define PSPHOT.INPUT.NUM"); 15 16 // loop over the available readouts 17 for (int i = 0; i < num; i++) { 18 if (!psphotSourceStatsReadout (config, view, "PSPHOT.INPUT", i, recipe, setWindow)) { 19 psError (PSPHOT_ERR_CONFIG, false, "failed to find initial detections for PSPHOT.INPUT entry %d", i); 20 return false; 21 } 22 } 23 return true; 24 } 25 26 bool psphotSourceStatsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe, bool setWindow) { 6 27 7 28 bool status = false; … … 10 31 psTimerStart ("psphot.stats"); 11 32 12 // select the appropriate recipe information 13 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE); 14 assert (recipe); 33 // find the currently selected readout 34 pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest 35 psAssert (file, "missing file?"); 36 37 pmReadout *readout = pmFPAviewThisReadout(view, file->fpa); 38 psAssert (readout, "missing readout?"); 39 40 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 41 psAssert (detections, "missing detections?"); 42 psAssert (!detections->newSources, "new sources already defined?"); 43 44 // XXX TEST: 45 if (detections->allSources) { 46 psphotMaskCosmicRayFootprintCheck(detections->allSources); 47 } 48 if (detections->newSources) { 49 psphotMaskCosmicRayFootprintCheck(detections->newSources); 50 } 15 51 16 52 // determine the number of allowed threads … … 21 57 22 58 // determine properties (sky, moments) of initial sources 23 float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS"); 24 if (!status) return NULL; 25 59 float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS"); 60 psAssert (status, "missing SKY_OUTER_RADIUS in recipe?"); 61 62 // XXX this seems like an arbitrary number... 26 63 OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius 27 64 28 65 char *breakPt = psMetadataLookupStr (&status, recipe, "BREAK_POINT"); 29 if (!status) return NULL; 66 psAssert (status, "missing BREAK_POINT?"); 67 68 float INNER = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS"); psAssert (status, "missing SKY_INNER_RADIUS"); 69 float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); psAssert (status, "missing MOMENTS_SN_MIN"); 70 71 // bit-masks to test for good/bad pixels 72 psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); 73 psAssert (maskVal, "missing MASK.PSPHOT"); 74 75 // bit-mask to mark pixels not used in analysis 76 psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); 77 psAssert (markVal, "missing MARK.PSPHOT"); 30 78 31 79 psArray *peaks = detections->peaks; 32 80 if (!peaks) { 33 81 psError(PS_ERR_UNEXPECTED_NULL, false, "No peaks found!"); 34 return NULL;82 return false; 35 83 } 36 84 37 85 // generate the array of sources, define the associated pixel 38 86 sources = psArrayAllocEmpty (peaks->n); 87 88 // if there are no peaks, we save the empty source array and return 89 if (!peaks->n) { 90 // save the new sources on the detection structure: 91 detections->newSources = sources; 92 return true; 93 } 39 94 40 95 for (int i = 0; i < peaks->n; i++) { … … 58 113 psArrayAdd (sources, 100, source); 59 114 psFree (source); 115 } 116 117 if (!strcasecmp (breakPt, "PEAKS")) { 118 psLogMsg ("psphot", PS_LOG_INFO, "%ld sources : %f sec\n", sources->n, psTimerMark ("psphot.stats")); 119 psLogMsg ("psphot", PS_LOG_INFO, "break point PEAKS, skipping MOMENTS\n"); 120 psphotVisualShowMoments (sources); 121 detections->newSources = sources; 122 return true; 123 } 124 125 if (setWindow) { 126 if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) { 127 psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!"); 128 psFree(sources); 129 return false; 130 } 131 } 132 133 // if we have measured the window, we will be saving the modified version of these recipe values on readout->analysis 134 float SIGMA = psMetadataLookupF32 (&status, readout->analysis, "MOMENTS_GAUSS_SIGMA"); 135 if (!status) { 136 SIGMA = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA"); 137 } 138 float RADIUS = psMetadataLookupF32 (&status, readout->analysis, "PSF_MOMENTS_RADIUS"); 139 if (!status) { 140 RADIUS = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS"); 141 } 142 143 // threaded measurement of the source magnitudes 144 int Nfail = 0; 145 int Nmoments = 0; 146 int Nfaint = 0; 147 148 // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts) 149 int Cx = 1, Cy = 1; 150 psphotChooseCellSizes (&Cx, &Cy, readout, nThreads); 151 152 psArray *cellGroups = psphotAssignSources (Cx, Cy, sources); 153 154 for (int i = 0; i < cellGroups->n; i++) { 155 156 psArray *cells = cellGroups->data[i]; 157 158 for (int j = 0; j < cells->n; j++) { 159 160 // allocate a job -- if threads are not defined, this just runs the job 161 psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS"); 162 163 psArrayAdd(job->args, 1, cells->data[j]); // sources 164 165 PS_ARRAY_ADD_SCALAR(job->args, INNER, PS_TYPE_F32); 166 PS_ARRAY_ADD_SCALAR(job->args, MIN_SN, PS_TYPE_F32); 167 PS_ARRAY_ADD_SCALAR(job->args, RADIUS, PS_TYPE_F32); 168 PS_ARRAY_ADD_SCALAR(job->args, SIGMA, PS_TYPE_F32); 169 170 PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK); 171 PS_ARRAY_ADD_SCALAR(job->args, markVal, PS_TYPE_IMAGE_MASK); 172 173 PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nmoments 174 PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfail 175 PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfaint 176 177 if (!psThreadJobAddPending(job)) { 178 psError(PS_ERR_UNKNOWN, false, "Unable to launch thread job PSPHOT_SOURCE_STATS"); 179 psFree (job); 180 psFree(sources); 181 return false; 182 } 183 psFree(job); 184 } 185 186 // wait for the threads to finish and manage results 187 if (!psThreadPoolWait (false)) { 188 psError(PS_ERR_UNKNOWN, false, "Failure in thread job PSPHOT_SOURCE_STATS"); 189 psFree(sources); 190 return false; 191 } 192 193 // we have only supplied one type of job, so we can assume the types here 194 psThreadJob *job = NULL; 195 while ((job = psThreadJobGetDone()) != NULL) { 196 if (job->args->n < 1) { 197 fprintf (stderr, "error with job\n"); 198 } else { 199 psScalar *scalar = NULL; 200 scalar = job->args->data[7]; 201 Nmoments += scalar->data.S32; 202 scalar = job->args->data[8]; 203 Nfail += scalar->data.S32; 204 scalar = job->args->data[9]; 205 Nfaint += scalar->data.S32; 206 } 207 psFree(job); 208 } 209 } 210 211 psFree (cellGroups); 212 213 psLogMsg ("psphot", PS_LOG_INFO, "%ld sources, %d moments, %d faint, %d failed: %f sec\n", sources->n, Nmoments, Nfaint, Nfail, psTimerMark ("psphot.stats")); 214 215 psphotVisualShowMoments (sources); 216 217 // save the new sources on the detection structure: 218 detections->newSources = sources; 219 220 221 if (detections->allSources) { 222 psphotMaskCosmicRayFootprintCheck(detections->allSources); 223 } 224 if (detections->newSources) { 225 psphotMaskCosmicRayFootprintCheck(detections->newSources); 226 } 227 228 return true; 229 } 230 231 // this function is currently only called by psphotCheckExtSources 232 bool psphotSourceStatsUpdate (psArray *sources, pmConfig *config, pmReadout *readout) { 233 234 bool status = false; 235 236 psTimerStart ("psphot.stats"); 237 238 // select the appropriate recipe information 239 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE); 240 assert (recipe); 241 242 // determine the number of allowed threads 243 int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads 244 if (!status) { 245 nThreads = 0; 246 } 247 248 // determine properties (sky, moments) of initial sources 249 float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS"); 250 if (!status) return false; 251 252 OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius 253 254 char *breakPt = psMetadataLookupStr (&status, recipe, "BREAK_POINT"); 255 if (!status) return false; 256 257 for (int i = 0; i < sources->n; i++) { 258 259 pmSource *source = sources->data[i]; 260 if (!source->peak) continue; // XXX how can we have a peak-less source? 261 262 // allocate space for moments 263 if (!source->moments) { 264 source->moments = pmMomentsAlloc(); 265 } 266 267 // allocate image, weight, mask arrays for each peak (square of radius OUTER) 268 pmSourceDefinePixels (source, readout, source->peak->x, source->peak->y, OUTER); 269 source->peak->assigned = true; 60 270 } 61 271 … … 67 277 } 68 278 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 } 279 // XXX how else could we get the window size in? 280 if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) { 281 psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!"); 282 return NULL; 74 283 } 75 284 … … 94 303 psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS"); 95 304 305 // XXX: this must match the above 96 306 psArrayAdd(job->args, 1, cells->data[j]); // sources 97 307 psArrayAdd(job->args, 1, recipe); … … 141 351 } 142 352 143 bool psphotSourceStatsUpdate (psArray *sources, pmConfig *config, pmReadout *readout) {144 145 bool status = false;146 147 psTimerStart ("psphot.stats");148 149 // select the appropriate recipe information150 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);151 assert (recipe);152 153 // determine the number of allowed threads154 int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads155 if (!status) {156 nThreads = 0;157 }158 159 // determine properties (sky, moments) of initial sources160 float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");161 if (!status) return NULL;162 163 OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius164 165 char *breakPt = psMetadataLookupStr (&status, recipe, "BREAK_POINT");166 if (!status) return NULL;167 168 for (int i = 0; i < sources->n; i++) {169 170 pmSource *source = sources->data[i];171 if (!source->peak) continue; // XXX how can we have a peak-less source?172 173 // allocate space for moments174 if (!source->moments) {175 source->moments = pmMomentsAlloc();176 }177 178 // allocate image, weight, mask arrays for each peak (square of radius OUTER)179 pmSourceDefinePixels (source, readout, source->peak->x, source->peak->y, OUTER);180 source->peak->assigned = true;181 }182 183 if (!strcasecmp (breakPt, "PEAKS")) {184 psLogMsg ("psphot", PS_LOG_INFO, "%ld sources : %f sec\n", sources->n, psTimerMark ("psphot.stats"));185 psLogMsg ("psphot", PS_LOG_INFO, "break point PEAKS, skipping MOMENTS\n");186 psphotVisualShowMoments (sources);187 return sources;188 }189 190 // XXX how else could we get the window size in?191 if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {192 psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");193 return NULL;194 }195 196 // threaded measurement of the source magnitudes197 int Nfail = 0;198 int Nmoments = 0;199 int Nfaint = 0;200 201 // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)202 int Cx = 1, Cy = 1;203 psphotChooseCellSizes (&Cx, &Cy, readout, nThreads);204 205 psArray *cellGroups = psphotAssignSources (Cx, Cy, sources);206 207 for (int i = 0; i < cellGroups->n; i++) {208 209 psArray *cells = cellGroups->data[i];210 211 for (int j = 0; j < cells->n; j++) {212 213 // allocate a job -- if threads are not defined, this just runs the job214 psThreadJob *job = psThreadJobAlloc ("PSPHOT_SOURCE_STATS");215 216 psArrayAdd(job->args, 1, cells->data[j]); // sources217 psArrayAdd(job->args, 1, recipe);218 PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nmoments219 PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfail220 PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nfaint221 222 if (!psThreadJobAddPending(job)) {223 psError(PS_ERR_UNKNOWN, false, "Unable to launch thread job PSPHOT_SOURCE_STATS");224 psFree (job);225 return NULL;226 }227 psFree(job);228 }229 230 // wait for the threads to finish and manage results231 if (!psThreadPoolWait (false)) {232 psError(PS_ERR_UNKNOWN, false, "Failure in thread job PSPHOT_SOURCE_STATS");233 return NULL;234 }235 236 // we have only supplied one type of job, so we can assume the types here237 psThreadJob *job = NULL;238 while ((job = psThreadJobGetDone()) != NULL) {239 if (job->args->n < 1) {240 fprintf (stderr, "error with job\n");241 } else {242 psScalar *scalar = NULL;243 scalar = job->args->data[2];244 Nmoments += scalar->data.S32;245 scalar = job->args->data[3];246 Nfail += scalar->data.S32;247 scalar = job->args->data[4];248 Nfaint += scalar->data.S32;249 }250 psFree(job);251 }252 }253 254 psFree (cellGroups);255 256 psLogMsg ("psphot", PS_LOG_INFO, "%ld sources, %d moments, %d faint, %d failed: %f sec\n", sources->n, Nmoments, Nfaint, Nfail, psTimerMark ("psphot.stats"));257 258 psphotVisualShowMoments (sources);259 260 return (sources);261 }262 263 353 bool psphotSourceStats_Threaded (psThreadJob *job) { 264 354 … … 268 358 269 359 psArray *sources = job->args->data[0]; 270 psMetadata *recipe = job->args->data[1]; 271 272 float INNER = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS"); 273 if (!status) return false; 274 float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); 275 if (!status) return false; 276 float RADIUS = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS"); 277 if (!status) return false; 278 float SIGMA = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA"); 279 if (!status) return false; 280 281 // bit-masks to test for good/bad pixels 282 psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); 283 assert (maskVal); 284 285 // bit-mask to mark pixels not used in analysis 286 psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); 287 assert (markVal); 360 361 float INNER = PS_SCALAR_VALUE(job->args->data[1],F32); 362 float MIN_SN = PS_SCALAR_VALUE(job->args->data[2],F32); 363 float RADIUS = PS_SCALAR_VALUE(job->args->data[3],F32); 364 float SIGMA = PS_SCALAR_VALUE(job->args->data[4],F32); 365 366 psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[5],PS_TYPE_IMAGE_MASK_DATA); 367 psImageMaskType markVal = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA); 288 368 289 369 // maskVal is used to test for rejected pixels, and must include markVal … … 349 429 350 430 // change the value of a scalar on the array (wrap this and put it in psArray.h) 351 scalar = job->args->data[ 2];431 scalar = job->args->data[7]; 352 432 scalar->data.S32 = Nmoments; 353 433 354 scalar = job->args->data[ 3];434 scalar = job->args->data[8]; 355 435 scalar->data.S32 = Nfail; 356 436 357 scalar = job->args->data[ 4];437 scalar = job->args->data[9]; 358 438 scalar->data.S32 = Nfaint; 359 439 … … 367 447 bool status; 368 448 369 float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); 370 if (!status) return false; 449 float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN"); psAssert (status, "missing MOMENTS_SN_MIN"); 450 float PSF_SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM"); psAssert (status, "missing PSF_SN_LIM"); 451 psF32 MOMENTS_AR_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_AR_MAX"); psAssert (status, "missing MOMENTS_AR_MAX"); 371 452 372 453 // XXX move this to a config file? … … 398 479 399 480 // choose a grid scale that is a fixed fraction of the psf sigma^2 400 psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(sigma[i]));401 psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));402 psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));481 float PSF_CLUMP_GRID_SCALE = 0.1*PS_SQR(sigma[i]); 482 float MOMENTS_SX_MAX = 2.0*PS_SQR(sigma[i]); 483 float MOMENTS_SY_MAX = 2.0*PS_SQR(sigma[i]); 403 484 404 485 // determine the PSF parameters from the source moment values 405 pmPSFClump psfClump = pmSourcePSFClump (NULL, sources, recipe);486 pmPSFClump psfClump = pmSourcePSFClump (NULL, NULL, sources, PSF_SN_LIM, PSF_CLUMP_GRID_SCALE, MOMENTS_SX_MAX, MOMENTS_SY_MAX, MOMENTS_AR_MAX); 406 487 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]); 407 488 … … 442 523 443 524 // choose a grid scale that is a fixed fraction of the psf sigma^2 444 psMetadataAddF32( recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(Sigma));445 psMetadataAddF32( recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));446 psMetadataAddF32( recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));447 psMetadataAddF32( recipe, PS_LIST_TAIL, "MOMENTS_GAUSS_SIGMA", PS_META_REPLACE, "moments limit", Sigma);448 psMetadataAddF32( recipe, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma);525 psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(Sigma)); 526 psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma)); 527 psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma)); 528 psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_GAUSS_SIGMA", PS_META_REPLACE, "moments limit", Sigma); 529 psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma); 449 530 450 531 psLogMsg ("psphot", 3, "using window function with sigma = %f\n", Sigma); 451 532 return true; 452 533 } 534 535 // if we use the footprints, the output peaks list contains both old and new peaks, 536 // otherwise it only contains the new peaks. 537
Note:
See TracChangeset
for help on using the changeset viewer.
