Changeset 19532
- Timestamp:
- Sep 11, 2008, 6:12:42 PM (18 years ago)
- Location:
- trunk
- Files:
-
- 14 edited
-
ppStack/src/ppStack.h (modified) (2 diffs)
-
ppStack/src/ppStackLoop.c (modified) (15 diffs)
-
ppStack/src/ppStackMatch.c (modified) (4 diffs)
-
ppStack/src/ppStackReadout.c (modified) (5 diffs)
-
ppStack/src/ppStackThread.c (modified) (1 diff)
-
psModules/src/imcombine/pmStack.c (modified) (7 diffs)
-
psModules/src/imcombine/pmStack.h (modified) (2 diffs)
-
psModules/src/imcombine/pmSubtraction.c (modified) (3 diffs)
-
psModules/src/imcombine/pmSubtraction.h (modified) (2 diffs)
-
psModules/src/imcombine/pmSubtractionEquation.c (modified) (1 diff)
-
psModules/src/imcombine/pmSubtractionIO.c (modified) (4 diffs)
-
psModules/src/imcombine/pmSubtractionKernels.h (modified) (1 diff)
-
psModules/src/imcombine/pmSubtractionMatch.c (modified) (3 diffs)
-
psModules/src/imcombine/pmSubtractionMatch.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/ppStack/src/ppStack.h
r19346 r19532 89 89 const psArray *readouts, // Input readouts 90 90 const psArray *regions, // Array with array of regions used in each PSF match 91 const psArray *kernels // Array with array of kernels used in each PSF match 91 const psArray *kernels, // Array with array of kernels used in each PSF match 92 const psVector *addVariance // Additional variance for rejection 92 93 ); 93 94 … … 128 129 129 130 /// Convolve image to match specified seeing 130 bool ppStackMatch(pmReadout *readout, // Readout to be convolved; replaced with output 131 psArray **regions, // Array of regions used in each PSF matching, returned 132 psArray **kernels, // Array of kernels used in each PSF matching, returned 131 bool ppStackMatch(pmReadout *readout, // Readout to be convolved; replaced with output 132 psArray **regions, // Array of regions used in each PSF matching, returned 133 psArray **kernels, // Array of kernels used in each PSF matching, returned 134 float *chi2, // Chi^2 from the stamps 133 135 const psArray *sources, // Array of sources 134 136 const pmPSF *psf, // Target PSF -
trunk/ppStack/src/ppStackLoop.c
r19505 r19532 390 390 psVector *inputMask = psVectorAlloc(num, PS_TYPE_U8); // Mask for inputs 391 391 psVectorInit(inputMask, 0); 392 psVector *matchChi2 = psVectorAlloc(num, PS_TYPE_F32); // chi^2 for stamps when matching 393 psVectorInit(matchChi2, NAN); 392 394 for (int i = 0; i < num; i++) { 393 395 psTrace("ppStack", 2, "Convolving input %d of %d to target PSF....\n", i, num); … … 402 404 psFree(rng); 403 405 psFree(inputMask); 406 psFree(matchChi2); 404 407 return false; 405 408 } … … 419 422 psFree(rng); 420 423 psFree(inputMask); 424 psFree(matchChi2); 421 425 return false; 422 426 } … … 425 429 psArray *regions = NULL, *kernels = NULL; // Regions and kernels used in subtraction 426 430 psArray *sources = haveSources ? globalSources : indSources->data[i]; // Sources for matching 427 if (!ppStackMatch(readout, ®ions, &kernels, sources, targetPSF, rng, config)) { 431 if (!ppStackMatch(readout, ®ions, &kernels, &matchChi2->data.F32[i], 432 sources, targetPSF, rng, config)) { 428 433 psErrorStackPrint(stderr, "Unable to match image %d --- ignoring.", i); 429 434 inputMask->data.U8[i] = PPSTACK_MASK_MATCH; … … 459 464 psFree(cells); 460 465 psFree(inputMask); 466 psFree(inputMask); 467 psFree(matchChi2); 461 468 return false; 462 469 } … … 473 480 memDump("preinitial"); 474 481 475 // Stack the convolv d files482 // Stack the convolved files 476 483 psTrace("ppStack", 1, "Initial stack of convolved images....\n"); 477 484 pmReadout *outRO = NULL; // Output readout … … 489 496 psFree(stack); 490 497 psFree(inputMask); 498 psFree(matchChi2); 491 499 psFree(exptimes); 492 500 psFree(cells); … … 502 510 psFree(stack); 503 511 psFree(inputMask); 512 psFree(matchChi2); 504 513 psFree(exptimes); 505 514 psFree(cells); … … 518 527 psFree(stack); 519 528 psFree(inputMask); 529 psFree(matchChi2); 520 530 psFree(view); 521 531 psFree(outRO); … … 546 556 psFree(cellList); 547 557 548 psFree(cells);558 psFree(cells); 549 559 550 560 bool status; // Status of read … … 559 569 psFree(stack); 560 570 psFree(inputMask); 571 psFree(matchChi2); 561 572 psFree(view); 562 573 psFree(outRO); … … 576 587 psArrayAdd(job->args, 1, subRegions); 577 588 psArrayAdd(job->args, 1, subKernels); 589 psArrayAdd(job->args, 1, matchChi2); 578 590 if (!psThreadJobAddPending(job)) { 579 591 psFree(job); … … 582 594 psFree(stack); 583 595 psFree(inputMask); 596 psFree(matchChi2); 584 597 psFree(view); 585 598 psFree(outRO); … … 596 609 psFree(stack); 597 610 psFree(inputMask); 611 psFree(matchChi2); 598 612 psFree(view); 599 613 psFree(outRO); … … 601 615 return false; 602 616 } 617 psFree(matchChi2); 603 618 604 619 // Harvest the jobs, gathering the inspection lists -
trunk/ppStack/src/ppStackMatch.c
r19486 r19532 15 15 PM_SOURCE_MODE_CR_LIMIT) // Mask to apply to input sources 16 16 17 //#define TESTING // Enable debugging output17 #define TESTING // Enable debugging output 18 18 19 19 … … 48 48 #endif 49 49 50 bool ppStackMatch(pmReadout *readout, psArray **regions, psArray **kernels, 50 bool ppStackMatch(pmReadout *readout, psArray **regions, psArray **kernels, float *chi2, 51 51 const psArray *sources, const pmPSF *psf, psRandom *rng, const pmConfig *config) 52 52 { … … 111 111 PM_SUBTRACTION_ANALYSIS_KERNEL); // Kernels 112 112 float vf = pmSubtractionVarianceFactor(kernels, 0.0, 0.0, false); // Variance factor 113 psMetadataItem *vfItem = psMetadataLookup( output->parent->concepts, "CELL.VARFACTOR");113 psMetadataItem *vfItem = psMetadataLookup(readout->parent->concepts, "CELL.VARFACTOR"); 114 114 if (!isfinite(vf)) { 115 115 vf = 1.0; … … 341 341 assert((*regions)->n == (*kernels)->n); 342 342 343 // Correct the variance for the chi^2 344 { 345 *chi2 = 0.0; 346 int num = 0; // Number of measurements of chi^2 347 psString regex = NULL; // Regular expression 348 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL); 349 psMetadataIterator *iter = psMetadataIteratorAlloc(output->analysis, PS_LIST_HEAD, regex); // Iterator 350 psFree(regex); 351 psMetadataItem *item = NULL;// Item from iteration 352 while ((item = psMetadataGetAndIncrement(iter))) { 353 assert(item->type == PS_DATA_UNKNOWN); 354 pmSubtractionKernels *kernels = item->data.V; // Convolution kernels 355 *chi2 += kernels->mean; 356 num++; 357 } 358 psFree(iter); 359 360 float vf = psMetadataLookupF32(NULL, readout->parent->concepts, "CELL.VARFACTOR"); // Variance factor 361 *chi2 /= vf * num; 362 } 363 343 364 // Renormalise the variances if desired 344 365 if (renorm) { -
trunk/ppStack/src/ppStackReadout.c
r19475 r19532 22 22 psArray *subRegions = args->data[3]; // Regions for PSF-matching 23 23 psArray *subKernels = args->data[4]; // Kernels for PSF-matching 24 25 psArray *inspect = ppStackReadoutInitial(config, outRO, thread->readouts, subRegions, subKernels); 24 psVector *addVariance = args->data[5]; // Additional variance when rejecting 25 26 psArray *inspect = ppStackReadoutInitial(config, outRO, thread->readouts, 27 subRegions, subKernels, addVariance); 26 28 27 29 job->results = inspect; … … 75 77 76 78 psArray *ppStackReadoutInitial(const pmConfig *config, pmReadout *outRO, const psArray *readouts, 77 const psArray *regions, const psArray *kernels )79 const psArray *regions, const psArray *kernels, const psVector *addVariance) 78 80 { 79 81 assert(config); … … 84 86 assert(readouts->n == regions->n); 85 87 assert(regions->n == kernels->n); 88 assert(addVariance && addVariance->n == readouts->n && addVariance->type.type == PS_TYPE_F32); 86 89 static int sectionNum = 0; // Section number; for debugging outputs 87 90 … … 127 130 } 128 131 129 stack->data[i] = pmStackDataAlloc(ro, weighting );132 stack->data[i] = pmStackDataAlloc(ro, weighting, addVariance->data.F32[i]); 130 133 } 131 134 … … 221 224 } 222 225 223 pmStackData *data = pmStackDataAlloc(ro, weighting );226 pmStackData *data = pmStackDataAlloc(ro, weighting, NAN); 224 227 data->reject = psMemIncrRefCounter(rejected->data[i]); 225 228 stack->data[i] = data; -
trunk/ppStack/src/ppStackThread.c
r19346 r19532 235 235 236 236 { 237 psThreadTask *task = psThreadTaskAlloc("PPSTACK_INITIAL_COMBINE", 5);237 psThreadTask *task = psThreadTaskAlloc("PPSTACK_INITIAL_COMBINE", 6); 238 238 task->function = &ppStackReadoutInitialThread; 239 239 psThreadTaskAdd(task); -
trunk/psModules/src/imcombine/pmStack.c
r19487 r19532 8 8 * @author GLG, MHPCC 9 9 * 10 * @version $Revision: 1.4 0$ $Name: not supported by cvs2svn $11 * @date $Date: 2008-09-1 1 20:52:16$10 * @version $Revision: 1.41 $ $Name: not supported by cvs2svn $ 11 * @date $Date: 2008-09-12 04:12:42 $ 12 12 * Copyright 2004-2007 Institute for Astronomy, University of Hawaii 13 13 * … … 30 30 #define PIXEL_LIST_BUFFER 100 // Number of entries to add to pixel list at a time 31 31 #define PIXEL_MAP_BUFFER 2 // Number of entries to add to pixel map at a time 32 //#define VARIANCE_FACTORS // Use variance factors when calculating the variances?32 #define VARIANCE_FACTORS // Use variance factors when calculating the variances? 33 33 #define NUM_DIRECT_STDEV 5 // For less than this number of values, measure stdev directly 34 34 … … 312 312 // Use variance to check that the two are consistent 313 313 float diff = pixelData->data.F32[0] - pixelData->data.F32[1]; 314 #if VARIANCE_FACTORS314 #ifdef VARIANCE_FACTORS 315 315 float sigma2 = pixelVariances->data.F32[0] * varFactors->data.F32[pixelSources->data.U16[0]] + 316 316 pixelVariances->data.F32[1] * varFactors->data.F32[pixelSources->data.U16[1]]; … … 346 346 float rej2 = PS_SQR(rej); // Rejection level squared 347 347 for (int i = 0; i < num; i++) { 348 #if VARIANCE_FACTORS348 #ifdef VARIANCE_FACTORS 349 349 pixelVariances->data.F32[i] *= rej2 * varFactors->data.F32[pixelSources->data.U16[i]]; 350 350 #else … … 538 538 539 539 /// Constructor 540 pmStackData *pmStackDataAlloc(pmReadout *readout, float weight )540 pmStackData *pmStackDataAlloc(pmReadout *readout, float weight, float addVariance) 541 541 { 542 542 pmStackData *data = psAlloc(sizeof(pmStackData)); // Stack data, to return … … 547 547 data->inspect = NULL; 548 548 data->weight = weight; 549 data->addVariance = addVariance; 549 550 550 551 return data; … … 602 603 } 603 604 varFactors->data.F32[i] = vf; 605 if (isfinite(data->addVariance)) { 606 varFactors->data.F32[i] *= data->addVariance; 607 } 604 608 if (!haveRejects && !data->inspect) { 605 609 data->inspect = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); -
trunk/psModules/src/imcombine/pmStack.h
r17005 r19532 8 8 * @author GLG, MHPCC 9 9 * 10 * @version $Revision: 1. 7$ $Name: not supported by cvs2svn $11 * @date $Date: 2008-0 3-17 21:38:43$10 * @version $Revision: 1.8 $ $Name: not supported by cvs2svn $ 11 * @date $Date: 2008-09-12 04:12:42 $ 12 12 * 13 13 * Copyright 2004-2007 Institute for Astronomy, University of Hawaii … … 31 31 psPixels *inspect; ///< Pixels to inspect 32 32 float weight; ///< Relative weighting for image 33 float addVariance; ///< Additional variance when rejecting 33 34 } pmStackData; 34 35 35 36 /// Constructor 36 37 pmStackData *pmStackDataAlloc(pmReadout *readout, ///< Warped readout (sky cell) 37 float weight ///< Weight to apply 38 float weight, ///< Weight to apply 39 float addVariance ///< Additional variance when rejecting 38 40 ); 39 41 -
trunk/psModules/src/imcombine/pmSubtraction.c
r19482 r19532 665 665 666 666 667 int pmSubtractionRejectStamps( float *rmsPtr, int *numPtr, pmSubtractionStampList *stamps,668 const psVector *deviations, psImage *subMask, float sigmaRej, 669 int footprint) 670 { 667 int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, pmSubtractionStampList *stamps, 668 const psVector *deviations, psImage *subMask, float sigmaRej, int footprint) 669 { 670 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); 671 671 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, -1); 672 672 PS_ASSERT_VECTOR_NON_NULL(deviations, -1); … … 678 678 // the distribution is actually something like a chi^2 or Student's t, both of which become Gaussian-like 679 679 // with large N. Therefore, let's just treat this as a Gaussian distribution. 680 681 kernels->mean = NAN; 682 kernels->rms = NAN; 683 kernels->numStamps = -1; 680 684 681 685 int numStamps = 0; // Number of used stamps … … 721 725 psTrace("psModules.imcombine", 1, "RMS deviation: %f\n", rms); 722 726 723 if (rmsPtr) { 724 *rmsPtr = rms; 725 } 726 if (numPtr) { 727 *numPtr = numStamps; 728 } 729 730 psLogMsg("psModules.imcombine", PS_LOG_INFO, "RMS deviation from %d stamps: %lf", numStamps, rms); 727 kernels->mean = mean; 728 kernels->rms = rms; 729 kernels->numStamps = numStamps; 730 731 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Mean deviation from %d stamps: %lf +/- %lf", 732 numStamps, mean, rms); 731 733 732 734 if (!isfinite(sigmaRej) || sigmaRej <= 0.0) { 733 // User just wanted to calculate and record the RMSfor posterity735 // User just wanted to calculate and record the deviation for posterity 734 736 return 0; 735 737 } -
trunk/psModules/src/imcombine/pmSubtraction.h
r19299 r19532 6 6 * @author GLG, MHPCC 7 7 * 8 * @version $Revision: 1.3 1$ $Name: not supported by cvs2svn $9 * @date $Date: 2008-0 8-30 02:28:07$8 * @version $Revision: 1.32 $ $Name: not supported by cvs2svn $ 9 * @date $Date: 2008-09-12 04:12:42 $ 10 10 * Copyright 2004-207 Institute for Astronomy, University of Hawaii 11 11 */ … … 64 64 65 65 /// Reject stamps 66 int pmSubtractionRejectStamps(float *rms, ///< RMS deviation, to return 67 int *num, ///< Number of good stamps, to return 66 int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, ///< Kernel parameters to update 68 67 pmSubtractionStampList *stamps, ///< Stamps 69 68 const psVector *deviations, ///< Deviations for each stamp -
trunk/psModules/src/imcombine/pmSubtractionEquation.c
r19299 r19532 1085 1085 } 1086 1086 } 1087 deviations->data.F32[i] = sqrtf(devNorm * deviation);1087 deviations->data.F32[i] = devNorm * deviation; 1088 1088 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n", 1089 1089 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]); -
trunk/psModules/src/imcombine/pmSubtractionIO.c
r19230 r19532 32 32 #define NAME_SOL1 "SOLUTION_1" // Solution for convolving image 1 33 33 #define NAME_SOL2 "SOLUTION_2" // Solution for convolving image 2 34 #define NAME_MEAN "MEAN" // Mean of chi^2 from stamps 35 #define NAME_RMS "RMS" // RMS of chi^2 from stamps 36 #define NAME_NUMSTAMPS "NUMSTAMPS" // Number of good stamps 34 37 35 38 #define FALLBACK_EXTNAME "SUBTRACTION_KERNEL" // Fallback extension name … … 159 162 psMetadataAddVector(row, PS_LIST_TAIL, NAME_SOL2, 0, "Solution vector 2", kernel->solution2); 160 163 } 164 psMetadataAddF32(row, PS_LIST_TAIL, NAME_MEAN, 0, "Mean of chi^2 from stamps", kernel->mean); 165 psMetadataAddF32(row, PS_LIST_TAIL, NAME_RMS, 0, "RMS of chi^2 from stamps", kernel->rms); 166 psMetadataAddF32(row, PS_LIST_TAIL, NAME_NUMSTAMPS, 0, "Number of good stamps", kernel->numStamps); 161 167 } 162 168 psFree(regions); … … 167 173 // CVS tags, used to identify the version of this file (in case incompatibilities are introduced) 168 174 psString cvsFile = psStringCopy("$RCSfile: pmSubtractionIO.c,v $"); 169 psString cvsRev = psStringCopy("$Revision: 1. 3$");170 psString cvsDate = psStringCopy("$Date: 2008-0 8-27 02:54:44$");175 psString cvsRev = psStringCopy("$Revision: 1.4 $"); 176 psString cvsDate = psStringCopy("$Date: 2008-09-12 04:12:42 $"); 171 177 psStringSubstitute(&cvsFile, NULL, "RCSfile: "); 172 178 psStringSubstitute(&cvsRev, NULL, "Revision: "); … … 338 344 TABLE_LOOKUP(int, S32, numRows, NAME_ROWS); 339 345 346 TABLE_LOOKUP(float, F32, mean, NAME_MEAN); 347 TABLE_LOOKUP(float, F32, rms, NAME_RMS); 348 TABLE_LOOKUP(int, S32, numStamps, NAME_NUMSTAMPS); 349 340 350 pmSubtractionKernels *kernels = pmSubtractionKernelsFromDescription(description, bg, mode); 341 351 kernels->numCols = numCols; 342 352 kernels->numRows = numRows; 353 kernels->mean = mean; 354 kernels->rms = rms; 355 kernels->numStamps = numStamps; 343 356 344 357 bool mdok; // Status of MD lookup -
trunk/psModules/src/imcombine/pmSubtractionKernels.h
r18287 r19532 42 42 int numCols, numRows; ///< Size of image (for normalisation), or zero to use image provided 43 43 psVector *solution1, *solution2; ///< Solution for the PSF matching 44 // Quality information 45 float mean, rms; ///< Mean and RMS of chi^2 from stamps 46 int numStamps; ///< Number of good stamps 44 47 } pmSubtractionKernels; 45 48 -
trunk/psModules/src/imcombine/pmSubtractionMatch.c
r19482 r19532 370 370 memCheck("kernels"); 371 371 372 float rmsStamps = NAN; // RMS for stamps373 int numStamps = 0; // Number of good stamps374 372 int numRejected = -1; // Number of rejected stamps in each iteration 375 373 for (int k = 0; k < iter && numRejected != 0; k++) { … … 407 405 408 406 psTrace("psModules.imcombine", 3, "Rejecting stamps...\n"); 409 numRejected = pmSubtractionRejectStamps(&rmsStamps, &numStamps, stamps, deviations, 410 subMask, rej, footprint); 407 numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej, footprint); 411 408 if (numRejected < 0) { 412 409 psError(PS_ERR_UNKNOWN, false, "Unable to reject stamps."); … … 430 427 goto MATCH_ERROR; 431 428 } 432 pmSubtractionRejectStamps(&rmsStamps, &numStamps, stamps, deviations, 433 subMask, NAN, footprint); 429 pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN, footprint); 434 430 psFree(deviations); 435 431 } 436 432 psFree(stamps); 437 433 stamps = NULL; 438 439 if (subMode == PM_SUBTRACTION_MODE_1 || subMode == PM_SUBTRACTION_MODE_DUAL) {440 psMetadataAddS32(conv1->analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_STAMPS_NUM,441 PS_META_DUPLICATE_OK, "Number of good stamps", numStamps);442 psMetadataAddF32(conv1->analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_STAMPS_RMS,443 PS_META_DUPLICATE_OK, "RMS deviation of stamps", rmsStamps);444 }445 if (subMode == PM_SUBTRACTION_MODE_2 || subMode == PM_SUBTRACTION_MODE_DUAL) {446 psMetadataAddS32(conv2->analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_STAMPS_NUM,447 PS_META_DUPLICATE_OK, "Number of good stamps", numStamps);448 psMetadataAddF32(conv2->analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_STAMPS_RMS,449 PS_META_DUPLICATE_OK, "RMS deviation of stamps", rmsStamps);450 }451 434 452 435 memCheck("solution"); -
trunk/psModules/src/imcombine/pmSubtractionMatch.h
r19299 r19532 9 9 #include <pmSubtractionStamps.h> 10 10 11 #define PM_SUBTRACTION_ANALYSIS_KERNEL "SUBTRACTION.KERNEL" // Name of kernel in the analysis metadata 12 #define PM_SUBTRACTION_ANALYSIS_MODE "SUBTRACTION.MODE" // Name of subtraction mode in the analysis metadata 13 #define PM_SUBTRACTION_ANALYSIS_REGION "SUBTRACTION.REGION" // Name of subtraction region in the analysis MD 14 #define PM_SUBTRACTION_ANALYSIS_STAMPS_RMS "SUBTRACTION.RMS" // Name of stamp rms in the analysis metadata 15 #define PM_SUBTRACTION_ANALYSIS_STAMPS_NUM "SUBTRACTION.NUM"// Name of the number of stamps in the analysis MD 16 #define PM_SUBTRACTION_ANALYSIS_VARFACTOR "SUBTRACTION.VARFACTOR"// Name of variance factor in the analysis MD 11 // Names for things put on the readout analysis metadata 12 #define PM_SUBTRACTION_ANALYSIS_KERNEL "SUBTRACTION.KERNEL" // Kernel used for convolving 13 #define PM_SUBTRACTION_ANALYSIS_MODE "SUBTRACTION.MODE" // Subtraction mode 14 #define PM_SUBTRACTION_ANALYSIS_REGION "SUBTRACTION.REGION" // Subtraction region 15 #define PM_SUBTRACTION_ANALYSIS_STAMPS_MEAN "SUBTRACTION.MEAN" // Stamp mean deviation 16 #define PM_SUBTRACTION_ANALYSIS_STAMPS_RMS "SUBTRACTION.RMS" // Stamp RMS deviation 17 #define PM_SUBTRACTION_ANALYSIS_STAMPS_NUM "SUBTRACTION.NUM" // Number of stamps 18 #define PM_SUBTRACTION_ANALYSIS_VARFACTOR "SUBTRACTION.VARFACTOR"// Variance factor 17 19 18 20
Note:
See TracChangeset
for help on using the changeset viewer.
