Changeset 5255
- Timestamp:
- Oct 10, 2005, 9:53:54 AM (21 years ago)
- Location:
- trunk/psModules
- Files:
-
- 12 added
- 4 edited
-
src/objects/Makefile.am (modified) (1 diff)
-
src/objects/pmModelGroup.c (added)
-
src/objects/pmModelGroup.h (added)
-
src/objects/pmObjects.c (modified) (78 diffs)
-
src/objects/pmObjects.h (modified) (6 diffs)
-
src/objects/pmPSF.c (added)
-
src/objects/pmPSF.h (added)
-
src/objects/pmPSFtry.c (added)
-
src/objects/pmPSFtry.h (added)
-
src/objects/psEllipse.c (added)
-
src/objects/psEllipse.h (added)
-
src/objects/psLibUtils.c (added)
-
src/objects/psLibUtils.h (added)
-
src/objects/psModulesUtils.c (added)
-
src/objects/psModulesUtils.h (added)
-
test/objects/tst_pmObjects01.c (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/objects/Makefile.am
r5170 r5255 3 3 libpsmoduleobjects_la_CPPFLAGS = $(SRCINC) $(PSMODULE_CFLAGS) 4 4 libpsmoduleobjects_la_LDFLAGS = -release $(PACKAGE_VERSION) 5 libpsmoduleobjects_la_SOURCES = pmObjects.c 5 libpsmoduleobjects_la_SOURCES = \ 6 pmObjects.c \ 7 pmPSF.c \ 8 pmPSFtry.c \ 9 pmModelGroup.c \ 10 psModulesUtils.c \ 11 psLibUtils.c \ 12 psEllipse.c 6 13 7 14 psmoduleincludedir = $(includedir) 8 15 psmoduleinclude_HEADERS = \ 9 pmObjects.h 16 pmObjects.h \ 17 pmPSF.h \ 18 pmPSFtry.h \ 19 pmModelGroup.h \ 20 psModulesUtils.h \ 21 psLibUtils.h \ 22 psEllipse.h -
trunk/psModules/src/objects/pmObjects.c
r5170 r5255 6 6 * @author EAM, IfA: significant modifications. 7 7 * 8 * @version $Revision: 1. 1$ $Name: not supported by cvs2svn $9 * @date $Date: 2005- 09-28 20:43:52$8 * @version $Revision: 1.2 $ $Name: not supported by cvs2svn $ 9 * @date $Date: 2005-10-10 19:53:40 $ 10 10 * 11 11 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 13 13 */ 14 14 15 #include<stdio.h> 16 #include<math.h> 15 #include <stdio.h> 16 #include <math.h> 17 #include <string.h> 17 18 #include "pslib.h" 18 #include "psConstants.h"19 19 #include "pmObjects.h" 20 20 #include "pmModelGroup.h" 21 21 /****************************************************************************** 22 22 pmPeakAlloc(): Allocate the pmPeak data structure and set appropriate members. … … 27 27 pmPeakType class) 28 28 { 29 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 29 30 pmPeak *tmp = (pmPeak *) psAlloc(sizeof(pmPeak)); 30 31 tmp->x = x; … … 33 34 tmp->class = class; 34 35 36 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 35 37 return(tmp); 36 38 } … … 42 44 pmMoments *pmMomentsAlloc() 43 45 { 46 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 44 47 pmMoments *tmp = (pmMoments *) psAlloc(sizeof(pmMoments)); 45 48 tmp->x = 0.0; 46 49 tmp->y = 0.0; 47 50 tmp->Sx = 0.0; 48 tmp->S x= 0.0;51 tmp->Sy = 0.0; 49 52 tmp->Sxy = 0.0; 50 53 tmp->Sum = 0.0; … … 53 56 tmp->nPixels = 0; 54 57 58 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 55 59 return(tmp); 56 60 } … … 58 62 static void modelFree(pmModel *tmp) 59 63 { 64 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 60 65 psFree(tmp->params); 61 66 psFree(tmp->dparams); 67 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 62 68 } 63 69 … … 65 71 pmModelAlloc(): Allocate the pmModel structure, along with its parameters, 66 72 and initialize the type member. Initialize the params to 0.0. 67 XXX EAM: changing params and dparams to psVector73 XXX EAM: simplifying code with pmModelParameterCount 68 74 *****************************************************************************/ 69 75 pmModel *pmModelAlloc(pmModelType type) 70 76 { 77 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 71 78 pmModel *tmp = (pmModel *) psAlloc(sizeof(pmModel)); 72 79 73 80 tmp->type = type; 74 81 tmp->chisq = 0.0; 75 switch (type) { 76 case PS_MODEL_GAUSS: 77 tmp->params = psVectorAlloc(7, PS_TYPE_F32); 78 tmp->dparams = psVectorAlloc(7, PS_TYPE_F32); 79 break; 80 case PS_MODEL_PGAUSS: 81 tmp->params = psVectorAlloc(7, PS_TYPE_F32); 82 tmp->dparams = psVectorAlloc(7, PS_TYPE_F32); 83 break; 84 case PS_MODEL_TWIST_GAUSS: 85 tmp->params = psVectorAlloc(11, PS_TYPE_F32); 86 tmp->dparams = psVectorAlloc(11, PS_TYPE_F32); 87 break; 88 case PS_MODEL_WAUSS: 89 tmp->params = psVectorAlloc(9, PS_TYPE_F32); 90 tmp->dparams = psVectorAlloc(9, PS_TYPE_F32); 91 break; 92 case PS_MODEL_SERSIC: 93 tmp->params = psVectorAlloc(8, PS_TYPE_F32); 94 tmp->dparams = psVectorAlloc(8, PS_TYPE_F32); 95 break; 96 case PS_MODEL_SERSIC_CORE: 97 tmp->params = psVectorAlloc(12, PS_TYPE_F32); 98 tmp->dparams = psVectorAlloc(12, PS_TYPE_F32); 99 break; 100 default: 82 tmp->nIter = 0; 83 psS32 Nparams = pmModelParameterCount(type); 84 if (Nparams == 0) { 101 85 psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType"); 102 86 return(NULL); 103 87 } 88 89 tmp->params = psVectorAlloc(Nparams, PS_TYPE_F32); 90 tmp->dparams = psVectorAlloc(Nparams, PS_TYPE_F32); 104 91 105 92 for (psS32 i = 0; i < tmp->params->n; i++) { … … 109 96 110 97 psMemSetDeallocator(tmp, (psFreeFunc) modelFree); 98 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 111 99 return(tmp); 112 100 } 113 101 114 102 /****************************************************************************** 115 XXX: We don't free pixels and mask since that caused a memory error. 116 We might need to increase the reference counter and decrease it here. 103 XXX EAM : we can now free these pixels - memory ref is incremented now 117 104 *****************************************************************************/ 118 105 static void sourceFree(pmSource *tmp) 119 106 { 107 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 120 108 psFree(tmp->peak); 121 // psFree(tmp->pixels); 122 // psFree(tmp->mask); 109 psFree(tmp->pixels); 110 psFree(tmp->weight); 111 psFree(tmp->mask); 123 112 psFree(tmp->moments); 124 113 psFree(tmp->modelPSF); 125 114 psFree(tmp->modelFLT); 115 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 126 116 } 127 117 … … 132 122 pmSource *pmSourceAlloc() 133 123 { 124 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 134 125 pmSource *tmp = (pmSource *) psAlloc(sizeof(pmSource)); 135 126 tmp->peak = NULL; 136 127 tmp->pixels = NULL; 128 tmp->weight = NULL; 137 129 tmp->mask = NULL; 138 130 tmp->moments = NULL; … … 142 134 psMemSetDeallocator(tmp, (psFreeFunc) sourceFree); 143 135 136 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 144 137 return(tmp); 145 138 } … … 159 152 psF32 threshold) 160 153 { 154 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 161 155 PS_ASSERT_VECTOR_NON_NULL(vector, NULL); 162 156 PS_ASSERT_VECTOR_NON_EMPTY(vector, NULL); … … 177 171 tmpVector = psVectorAlloc(0, PS_TYPE_U32); 178 172 } 173 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 179 174 return(tmpVector); 180 175 } … … 241 236 } 242 237 238 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 243 239 return(tmpVector); 244 240 } … … 248 244 psVector containing the specified row of data from the psImage. 249 245 250 XXX: Is there a better way to do this? 246 XXX: Is there a better way to do this? 247 XXX EAM: does this really need to alloc a new vector??? 251 248 *****************************************************************************/ 252 249 static psVector *getRowVectorFromImage(psImage *image, 253 250 psU32 row) 254 251 { 252 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 255 253 PS_ASSERT_IMAGE_NON_NULL(image, NULL); 256 254 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, NULL); … … 260 258 tmpVector->data.F32[col] = image->data.F32[row][col]; 261 259 } 260 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 262 261 return(tmpVector); 263 262 } … … 276 275 pmPeakType type) 277 276 { 277 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 278 278 pmPeak *tmpPeak = pmPeakAlloc(col, row, counts, type); 279 279 … … 283 283 } 284 284 psArrayAdd(list, 100, tmpPeak); 285 285 psFree (tmpPeak); 286 // XXX EAM : is this free appropriate? (does psArrayAdd increment memory counter?) 287 288 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 286 289 return(list); 287 290 } … … 308 311 psF32 threshold) 309 312 { 313 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 310 314 PS_ASSERT_IMAGE_NON_NULL(image, NULL); 311 315 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, NULL); 312 316 if ((image->numRows == 1) || (image->numCols == 1)) { 313 317 psError(PS_ERR_UNKNOWN, true, "Currently, input image must have at least 2 rows and 2 columns."); 318 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 314 319 return(NULL); 315 320 } … … 364 369 } 365 370 } 371 psFree (tmpRow); 372 psFree (row1); 366 373 367 374 // … … 369 376 // 370 377 if (image->numRows == 1) { 378 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 371 379 return(list); 372 380 } … … 442 450 } 443 451 } else { 444 psError(PS_ERR_UNKNOWN, true, "peak specified valid column range.");452 psError(PS_ERR_UNKNOWN, true, "peak specified outside valid column range."); 445 453 } 446 454 447 455 } 456 psFree (tmpRow); 457 psFree (row1); 448 458 } 449 459 … … 484 494 } 485 495 } else { 486 psError(PS_ERR_UNKNOWN, true, "peak specified valid colum range."); 487 } 488 } 496 psError(PS_ERR_UNKNOWN, true, "peak specified outside valid column range."); 497 } 498 } 499 psFree (tmpRow); 500 psFree (row1); 501 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 489 502 return(list); 490 503 } … … 495 508 psS32 y) 496 509 { 497 510 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 498 511 if ((x >= valid.x0) && 499 512 (x <= valid.x1) && 500 513 (y >= valid.y0) && 501 514 (y <= valid.y1)) { 515 psTrace(__func__, 4, "---- %s(true) end ----\n", __func__); 502 516 return(true); 503 517 } 504 518 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 505 519 return(false); 506 520 } … … 516 530 517 531 XXX: changed API to create a NEW output psArray (should change name as well) 532 533 XXX: Do we free the psList elements of those culled peaks? 534 535 XXX EAM : do we still need pmCullPeaks, or only pmPeaksSubset? 518 536 *****************************************************************************/ 519 537 psList *pmCullPeaks(psList *peaks, … … 521 539 const psRegion valid) 522 540 { 541 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 523 542 PS_ASSERT_PTR_NON_NULL(peaks, NULL); 524 // PS_ASSERT_PTR_NON_NULL(valid, NULL);525 543 526 544 psListElem *tmpListElem = (psListElem *) peaks->head; … … 539 557 } 540 558 559 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 541 560 return(peaks); 542 561 } … … 544 563 // XXX EAM: I changed this to return a new, subset array 545 564 // rather than alter the existing one 546 psArray *pmPeaksSubset(psArray *peaks, psF32 maxValue, const psRegion valid) 547 { 565 // XXX: Fix the *valid pointer. 566 psArray *pmPeaksSubset( 567 psArray *peaks, 568 psF32 maxValue, 569 const psRegion valid) 570 { 571 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 548 572 PS_ASSERT_PTR_NON_NULL(peaks, NULL); 549 573 … … 561 585 psArrayAdd (output, 200, tmpPeak); 562 586 } 587 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 563 588 return(output); 564 589 } … … 601 626 members. 602 627 *****************************************************************************/ 603 pmSource *pmSourceLocalSky(const psImage *image, 604 const pmPeak *peak, 605 psStatsOptions statsOptions, 606 psF32 innerRadius, 607 psF32 outerRadius) 608 { 609 PS_ASSERT_IMAGE_NON_NULL(image, NULL); 610 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, NULL); 611 PS_ASSERT_PTR_NON_NULL(peak, NULL); 612 PS_FLOAT_COMPARE(0.0, innerRadius, NULL); 613 PS_FLOAT_COMPARE(innerRadius, outerRadius, NULL); 614 psS32 innerRadiusS32 = (psS32) innerRadius; 615 psS32 outerRadiusS32 = (psS32) outerRadius; 616 617 // 618 // We define variables for code readability. 619 // 620 // XXX: Since the peak->xy coords are in image, not subImage coords, 621 // these variables should be renamed for clarity (imageCenterRow, etc). 622 // 623 // peak->x,y is guaranteed to be on image 624 psS32 SubImageCenterRow = peak->y; 625 psS32 SubImageCenterCol = peak->x; 626 627 // XXX EAM : I added this code to stay on the image. So did George 628 psS32 SubImageStartRow = PS_MAX(0, SubImageCenterRow - outerRadiusS32); 629 psS32 SubImageEndRow = PS_MIN(image->numRows - 1, SubImageCenterRow + outerRadiusS32); 630 psS32 SubImageStartCol = PS_MAX(0, SubImageCenterCol - outerRadiusS32); 631 psS32 SubImageEndCol = PS_MIN(image->numCols - 1, SubImageCenterCol + outerRadiusS32); 632 // AnulusWidth == number of pixels width in the annulus. We add one since 633 // the pixels at the inner AND outher radius are included. 634 psS32 AnulusWidth = 1 + (outerRadiusS32 - innerRadiusS32); 635 // Example: assume an outer/inner radius of 20/10. Then the subimage 636 // should have width/length of 40. An 18-by-18 interior region will 637 // be masked. 638 // printf("pmSourceLocalSky(): innerRadiusS32 is %d\n", innerRadiusS32); 639 // printf("pmSourceLocalSky(): outerRadiusS32 is %d\n", outerRadiusS32); 640 // printf("pmSourceLocalSky(): AnulusWidth is %d\n", AnulusWidth); 641 642 // XXX EAM : these tests should not be needed: we can never hit this error because of above 643 # if (1) 644 645 if (SubImageStartRow < 0) { 646 psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n", 647 SubImageStartRow); 648 return(NULL); 649 } 650 if (SubImageEndRow >= image->numRows) { 651 psError(PS_ERR_UNKNOWN, true, "Sub image endRow is outside image boundaries (%d).\n", 652 SubImageEndRow); 653 return(NULL); 654 } 655 if (SubImageStartCol < 0) { 656 psError(PS_ERR_UNKNOWN, true, "Sub image startCol is outside image boundaries (%d).\n", 657 SubImageStartCol); 658 return(NULL); 659 } 660 if (SubImageEndCol >= image->numCols) { 661 psError(PS_ERR_UNKNOWN, true, "Sub image endCol is outside image boundaries (%d).\n", 662 SubImageEndCol); 663 return(NULL); 664 } 665 # endif 666 667 // 668 // Grab a subimage of the original image of size (2 * outerRadius). 669 // 670 // XXX: Must fix for new psImageSubset 671 // psImage *subImage = psImageSubset((psImage *) image, 672 // SubImageStartCol, 673 // SubImageStartRow, 674 // SubImageEndCol, 675 // SubImageEndRow); 676 // printf("pmSourceLocalSky: subimage width/length is (%d, %d)\n", subImage->numCols, subImage->numRows); 677 psRegion tmpRegion = psRegionSet(SubImageStartCol, 678 SubImageEndCol, 679 SubImageStartRow, 680 SubImageEndRow); 681 psImage *subImage = psImageSubset((psImage *) image, tmpRegion); 682 683 psImage *subImageMask = psImageAlloc(subImage->numCols, 684 subImage->numRows, 685 PS_TYPE_U8); 686 687 // 688 // Loop through the subimage mask, initialize mask to 0. 689 // 690 for (psS32 row = 0 ; row < subImageMask->numRows; row++) { 691 for (psS32 col = 0 ; col < subImageMask->numCols; col++) { 692 subImageMask->data.U8[row][col] = 0; 693 } 694 } 695 696 // 697 // Loop through the subimage, mask off pixels in the inner square. 698 // XXX this uses a static mask value of 1 699 // 700 for (psS32 row = AnulusWidth; row <= (subImageMask->numRows - AnulusWidth) - 1; row++) { 701 for (psS32 col = AnulusWidth; col <= (subImageMask->numCols - AnulusWidth) - 1; col++) { 702 subImageMask->data.U8[row][col] = 1; 703 } 704 } 705 706 707 // for (psS32 row = 0 ; row < subImage->numRows; row++) { 708 // for (psS32 col = 0 ; col < subImage->numCols; col++) { 709 // printf("(%d) ", subImageMask->data.U8[row][col]); 710 // } 711 // printf("\n"); 712 // } 713 714 // 715 // Allocate the myStats structure, then call psImageStats(), which will 716 // calculate the specified statistic. 717 // 628 629 630 631 632 633 634 635 636 637 bool pmSourceLocalSky( 638 pmSource *source, 639 psStatsOptions statsOptions, 640 psF32 Radius) 641 { 642 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 643 PS_ASSERT_PTR_NON_NULL(source, false); 644 PS_ASSERT_IMAGE_NON_NULL(source->pixels, false); 645 PS_ASSERT_IMAGE_NON_NULL(source->mask, false); 646 PS_ASSERT_PTR_NON_NULL(source->peak, false); 647 PS_ASSERT_INT_POSITIVE(Radius, false); 648 PS_ASSERT_INT_NONNEGATIVE(Radius, false); 649 650 psImage *image = source->pixels; 651 psImage *mask = source->mask; 652 pmPeak *peak = source->peak; 653 psRegion srcRegion; 654 655 srcRegion = psRegionForSquare(peak->x, peak->y, Radius); 656 srcRegion = psRegionForImage(mask, srcRegion); 657 658 psImageMaskRegion(mask, srcRegion, "OR", PSPHOT_MASK_MARKED); 718 659 psStats *myStats = psStatsAlloc(statsOptions); 719 myStats = psImageStats(myStats, subImage, subImageMask, 1); 720 721 // 722 // Create the output mySource, and set appropriate members. 723 // 724 pmSource *mySource = pmSourceAlloc(); 725 mySource->peak = (pmPeak *) peak; 726 mySource->moments = pmMomentsAlloc(); 660 myStats = psImageStats(myStats, image, mask, 0xff); 661 psImageMaskRegion(mask, srcRegion, "AND", ~PSPHOT_MASK_MARKED); 662 727 663 psF64 tmpF64; 728 664 p_psGetStatValue(myStats, &tmpF64); 729 mySource->moments->Sky = (psF32) tmpF64;730 mySource->pixels = subImage;731 mySource->mask = subImageMask;732 733 //734 // Free things. XXX: This should be static memory.735 //736 665 psFree(myStats); 737 666 738 return(mySource); 739 } 740 741 /****************************************************************************** 742 bool checkRadius(*peak, radius, x, y): private function which simply 743 determines if the (x, y) point is within the radius of the specified peak. 744 745 XXX: macro this for performance. 746 *****************************************************************************/ 747 static bool checkRadius(pmPeak *peak, 748 psF32 radius, 749 psS32 x, 750 psS32 y) 751 { 752 if (PS_SQR(radius) >= (psF32) (PS_SQR(x - peak->x) + PS_SQR(y - peak->y))) { 753 return(true); 754 } 755 756 return(false); 667 if (isnan(tmpF64)) { 668 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 669 return(false); 670 } 671 source->moments = pmMomentsAlloc(); 672 source->moments->Sky = (psF32) tmpF64; 673 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 674 return (true); 757 675 } 758 676 … … 770 688 psF32 y) 771 689 { 690 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 772 691 /// XXX EAM should compare with hypot (x,y) for speed 773 692 if ((PS_SQR(x - xCenter) + PS_SQR(y - yCenter)) < PS_SQR(radius)) { … … 775 694 } 776 695 696 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 777 697 return(false); 778 698 } … … 787 707 pmSource->peak 788 708 pmSource->pixels 709 pmSource->weight 710 pmSource->mask 789 711 790 712 XXX: The peak calculations are done in image coords, not subImage coords. 791 713 792 XXX: mask values? 793 *****************************************************************************/ 794 pmSource *pmSourceMoments(pmSource *source, 795 psF32 radius) 796 { 797 PS_ASSERT_PTR_NON_NULL(source, NULL); 798 PS_ASSERT_PTR_NON_NULL(source->peak, NULL); 799 PS_ASSERT_PTR_NON_NULL(source->pixels, NULL); 800 PS_FLOAT_COMPARE(0.0, radius, NULL); 714 XXX EAM : this version clips input pixels on S/N 715 XXX EAM : this version returns false for several reasons 716 *****************************************************************************/ 717 # define VALID_RADIUS(X,Y,RAD2) (((RAD2) >= (PS_SQR(X) + PS_SQR(Y))) ? 1 : 0) 718 719 bool pmSourceMoments(pmSource *source, 720 psF32 radius) 721 { 722 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 723 PS_ASSERT_PTR_NON_NULL(source, false); 724 PS_ASSERT_PTR_NON_NULL(source->peak, false); 725 PS_ASSERT_PTR_NON_NULL(source->pixels, false); 726 PS_ASSERT_PTR_NON_NULL(source->mask, false); 727 PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false); 801 728 802 729 // … … 816 743 // XY = SUM (x - xc)*(y - yc)*(z - sky) 817 744 // 818 psF32 Sum = 0.0;819 745 psF32 peakPixel = -PS_MAX_F32; 820 746 psS32 numPixels = 0; 747 psF32 Sum = 0.0; 821 748 psF32 X1 = 0.0; 822 749 psF32 Y1 = 0.0; … … 824 751 psF32 Y2 = 0.0; 825 752 psF32 XY = 0.0; 826 psF32 x = 0; 827 psF32 y = 0; 828 // 753 psF32 x = 0; 754 psF32 y = 0; 755 psF32 R2 = PS_SQR(radius); 756 757 psF32 xPeak = source->peak->x; 758 psF32 yPeak = source->peak->y; 759 829 760 // XXX why do I get different results for these two methods of finding Sx? 830 761 // XXX Sx, Sy would be better measured if we clip pixels close to sky … … 834 765 // proceed with the moments calculation. need to do two loops for a 835 766 // numerically stable result. first loop: get the sums. 836 // 767 // XXX EAM : mask == 0 is valid 768 837 769 for (psS32 row = 0; row < source->pixels->numRows ; row++) { 838 770 for (psS32 col = 0; col < source->pixels->numCols ; col++) { 839 if ((source->mask != NULL) && (source->mask->data.U8[row][col] != 0)) { 840 psS32 imgColCoord = col + source->pixels->col0; 841 psS32 imgRowCoord = row + source->pixels->row0; 842 if (checkRadius(source->peak, 843 radius, 844 imgColCoord, 845 imgRowCoord)) { 846 psF32 xDiff = (psF32) (imgColCoord - source->peak->x); 847 psF32 yDiff = (psF32) (imgRowCoord - source->peak->y); 848 psF32 pDiff = source->pixels->data.F32[row][col] - sky; 849 850 Sum+= pDiff; 851 X1+= xDiff * pDiff; 852 Y1+= yDiff * pDiff; 853 XY+= xDiff * yDiff * pDiff; 854 855 X2+= PS_SQR(xDiff) * pDiff; 856 Y2+= PS_SQR(yDiff) * pDiff; 857 858 if (source->pixels->data.F32[row][col] > peakPixel) { 859 peakPixel = source->pixels->data.F32[row][col]; 860 } 861 numPixels++; 862 } 863 } 864 } 865 } 771 if ((source->mask != NULL) && (source->mask->data.U8[row][col])) 772 continue; 773 774 psF32 xDiff = col + source->pixels->col0 - xPeak; 775 psF32 yDiff = row + source->pixels->row0 - yPeak; 776 777 // XXX EAM : calculate xDiff, yDiff up front; 778 // radius is just a function of (xDiff, yDiff) 779 if (!VALID_RADIUS(xDiff, yDiff, R2)) 780 continue; 781 782 psF32 pDiff = source->pixels->data.F32[row][col] - sky; 783 784 // XXX EAM : check for valid S/N in pixel 785 // XXX EAM : should this limit be user-defined? 786 if (pDiff / sqrt(source->weight->data.F32[row][col]) < 1) 787 continue; 788 789 Sum += pDiff; 790 X1 += xDiff * pDiff; 791 Y1 += yDiff * pDiff; 792 XY += xDiff * yDiff * pDiff; 793 794 X2 += PS_SQR(xDiff) * pDiff; 795 Y2 += PS_SQR(yDiff) * pDiff; 796 797 peakPixel = PS_MAX (source->pixels->data.F32[row][col], peakPixel); 798 numPixels++; 799 } 800 } 801 // XXX EAM - the limit is a bit arbitrary. make it user defined? 802 if ((numPixels < 3) || (Sum <= 0)) { 803 psTrace (".psModules.pmSourceMoments", 5, "no valid pixels for source\n"); 804 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 805 return (false); 806 } 807 808 psTrace (".psModules.pmSourceMoments", 5, 809 "sky: %f Sum: %f X1: %f Y1: %f X2: %f Y2: %f XY: %f Npix: %d\n", 810 sky, Sum, X1, Y1, X2, Y2, XY, numPixels); 866 811 867 812 // … … 872 817 x = X1/Sum; 873 818 y = Y1/Sum; 874 source->moments->x = x + ((psF32) source->peak->x); 875 source->moments->y = y + ((psF32) source->peak->y); 876 877 source->moments->Sxy = XY/Sum; 819 if ((fabs(x) > radius) || (fabs(y) > radius)) { 820 psTrace (".psModules.pmSourceMoments", 5, 821 "large centroid swing; invalid peak %d, %d\n", 822 source->peak->x, source->peak->y); 823 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 824 return (false); 825 } 826 827 source->moments->x = x + xPeak; 828 source->moments->y = y + yPeak; 829 830 // XXX EAM : Sxy needs to have x*y subtracted 831 source->moments->Sxy = XY/Sum - x*y; 878 832 source->moments->Sum = Sum; 879 833 source->moments->Peak = peakPixel; … … 883 837 source->moments->Sx = sqrt(PS_MAX(X2/Sum - PS_SQR(x), 0)); 884 838 source->moments->Sy = sqrt(PS_MAX(Y2/Sum - PS_SQR(y), 0)); 885 return(source); 886 887 // XXX EAM : the following code should be the same as above, but it is not very stable: ignore it 888 # if (0) 889 // 890 // second loop: get the difference sums 891 // 892 X2 = Y2 = 0; 893 for (psS32 row = 0; row < source->pixels->numRows ; row++) { 894 for (psS32 col = 0; col < source->pixels->numCols ; col++) { 895 if ((source->mask != NULL) && (source->mask->data.U8[row][col] != 0)) { 896 psS32 imgColCoord = col + source->pixels->col0; 897 psS32 imgRowCoord = row + source->pixels->row0; 898 if (checkRadius(source->peak, 899 radius, 900 imgColCoord, 901 imgRowCoord)) { 902 psF32 xDiff = (psF32) (imgColCoord - source->peak->x); 903 psF32 yDiff = (psF32) (imgRowCoord - source->peak->y); 904 psF32 pDiff = source->pixels->data.F32[row][col] - sky; 905 906 Sum+= pDiff; 907 X2+= PS_SQR(xDiff - x) * pDiff; 908 Y2+= PS_SQR(yDiff - y) * pDiff; 909 } 910 } 911 } 912 } 913 914 // 915 // second moment X = sqrt (X2/Sum) 916 // 917 source->moments->Sx = (X2/Sum); 918 source->moments->Sy = (Y2/Sum); 919 return(source); 920 # endif 839 840 psTrace (".psModules.pmSourceMoments", 4, 841 "sky: %f Sum: %f x: %f y: %f Sx: %f Sy: %f Sxy: %f\n", 842 sky, Sum, source->moments->x, source->moments->y, 843 source->moments->Sx, source->moments->Sy, source->moments->Sxy); 844 845 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 846 return(true); 921 847 } 922 848 … … 924 850 int pmComparePeakAscend (const void **a, const void **b) 925 851 { 852 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 926 853 pmPeak *A = *(pmPeak **)a; 927 854 pmPeak *B = *(pmPeak **)b; … … 930 857 931 858 diff = A->counts - B->counts; 932 if (diff < FLT_EPSILON) 859 if (diff < FLT_EPSILON) { 860 psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__); 933 861 return (-1); 934 if (diff > FLT_EPSILON) 862 } else if (diff > FLT_EPSILON) { 863 psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__); 935 864 return (+1); 865 } 866 psTrace(__func__, 3, "---- %s(0) end ----\n", __func__); 936 867 return (0); 937 868 } … … 939 870 int pmComparePeakDescend (const void **a, const void **b) 940 871 { 872 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 941 873 pmPeak *A = *(pmPeak **)a; 942 874 pmPeak *B = *(pmPeak **)b; … … 945 877 946 878 diff = A->counts - B->counts; 947 if (diff < FLT_EPSILON) 879 if (diff < FLT_EPSILON) { 880 psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__); 948 881 return (+1); 949 if (diff > FLT_EPSILON) 882 } else if (diff > FLT_EPSILON) { 883 psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__); 950 884 return (-1); 885 } 886 psTrace(__func__, 3, "---- %s(0) end ----\n", __func__); 951 887 return (0); 952 888 } 953 889 954 890 /****************************************************************************** 955 pmSourceRoughClass(source, metadata): make a guess at the source 956 classification. 957 958 XXX: This is not useable code, as of the release date. There remains a fair 959 bit of coding to be completed. 960 961 XXX: The sigX and sigY stuff in the SDRS is unclear. 962 963 XXX: How can this function ever return FALSE? 964 *****************************************************************************/ 965 966 # define NPIX 10 967 # define SCALE 0.1 968 969 // XXX I am ignore memory freeing issues (EAM) 970 bool pmSourceRoughClass(psArray *sources, psMetadata *metadata) 971 { 972 PS_ASSERT_PTR_NON_NULL(sources, false); 973 PS_ASSERT_PTR_NON_NULL(metadata, false); 974 psBool rc = true; 891 pmSourcePSFClump(source, metadata): Find the likely PSF clump in the 892 sigma-x, sigma-y plane. return 0,0 clump in case of error. 893 *****************************************************************************/ 894 895 // XXX EAM include a S/N cutoff in selecting the sources? 896 pmPSFClump pmSourcePSFClump(psArray *sources, psMetadata *metadata) 897 { 898 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 899 900 # define NPIX 10 901 # define SCALE 0.1 902 975 903 psArray *peaks = NULL; 976 psF32 clumpX = 0.0; 977 psF32 clumpDX = 0.0; 978 psF32 clumpY = 0.0; 979 psF32 clumpDY = 0.0; 904 pmPSFClump emptyClump = {0.0, 0.0, 0.0, 0.0}; 905 pmPSFClump psfClump = emptyClump; 906 907 PS_ASSERT_PTR_NON_NULL(sources, emptyClump); 908 PS_ASSERT_PTR_NON_NULL(metadata, emptyClump); 980 909 981 910 // find the sigmaX, sigmaY clump … … 986 915 987 916 // construct a sigma-plane image 917 // psImageAlloc does zero the data 988 918 splane = psImageAlloc (NPIX/SCALE, NPIX/SCALE, PS_TYPE_F32); 919 for (int i = 0; i < splane->numRows; i++) 920 { 921 memset (splane->data.F32[i], 0, splane->numCols*sizeof(PS_TYPE_F32)); 922 } 989 923 990 924 // place the sources in the sigma-plane image (ignore 0,0 values?) … … 992 926 { 993 927 pmSource *tmpSrc = (pmSource *) sources->data[i]; 994 PS_ASSERT_PTR_NON_NULL(tmpSrc, false); // just skip this one? 995 PS_ASSERT_PTR_NON_NULL(tmpSrc->moments, false); // just skip this one? 928 if (tmpSrc == NULL) { 929 continue; 930 } 931 if (tmpSrc->moments == NULL) { 932 continue; 933 } 996 934 997 935 // Sx,Sy are limited at 0. a peak at 0,0 is artificial … … 1022 960 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump threshold is %f\n", stats[0].max/2); 1023 961 1024 } 962 psFree (splane); 963 psFree (stats); 964 965 } 966 // XXX EAM : possible errors: 967 // 1) no peak in splane 968 // 2) no significant peak in splane 1025 969 1026 970 // measure statistics on Sx, Sy if Sx, Sy within range of clump … … 1036 980 psArraySort (peaks, pmComparePeakDescend); 1037 981 clump = peaks->data[0]; 1038 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump is at %d, %d \n", clump->x, clump->y);982 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->counts); 1039 983 1040 984 // define section window for clump … … 1077 1021 1078 1022 stats = psVectorStats (stats, tmpSx, NULL, NULL, 0); 1079 clumpX = stats->clippedMean;1080 clumpDX = stats->clippedStdev;1023 psfClump.X = stats->clippedMean; 1024 psfClump.dX = stats->clippedStdev; 1081 1025 1082 1026 stats = psVectorStats (stats, tmpSy, NULL, NULL, 0); 1083 clumpY = stats->clippedMean;1084 clumpDY = stats->clippedStdev;1085 1086 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump X, Y: %f, %f\n", clumpX, clumpY);1087 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump DX, DY: %f, %f\n", clumpDX, clumpDY);1027 psfClump.Y = stats->clippedMean; 1028 psfClump.dY = stats->clippedStdev; 1029 1030 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump X, Y: %f, %f\n", psfClump.X, psfClump.Y); 1031 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump DX, DY: %f, %f\n", psfClump.dX, psfClump.dY); 1088 1032 // these values should be pushed on the metadata somewhere 1089 } 1090 1091 int Nsat = 0; 1092 int Ngal = 0; 1093 int Nfaint = 0; 1094 int Nstar = 0; 1095 int Npsf = 0; 1096 int Ncr = 0; 1033 1034 psFree (stats); 1035 psFree (peaks); 1036 psFree (tmpSx); 1037 psFree (tmpSy); 1038 } 1039 1040 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1041 return (psfClump); 1042 } 1043 1044 /****************************************************************************** 1045 pmSourceRoughClass(source, metadata): make a guess at the source 1046 classification. 1047 1048 XXX: push the clump info into the metadata? 1049 1050 XXX: How can this function ever return FALSE? 1051 1052 XXX EAM : add the saturated mask value to metadata 1053 *****************************************************************************/ 1054 1055 bool pmSourceRoughClass(psArray *sources, psMetadata *metadata, pmPSFClump clump) 1056 { 1057 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1058 1059 psBool rc = true; 1060 1061 int Nsat = 0; 1062 int Ngal = 0; 1063 int Nstar = 0; 1064 int Npsf = 0; 1065 int Ncr = 0; 1066 int Nsatstar = 0; 1067 1097 1068 psVector *starsn = psVectorAlloc (sources->n, PS_TYPE_F32); 1098 1069 starsn->n = 0; 1070 1071 // check return status value (do these exist?) 1072 bool status; 1073 psF32 RDNOISE = psMetadataLookupF32 (&status, metadata, "RDNOISE"); 1074 psF32 GAIN = psMetadataLookupF32 (&status, metadata, "GAIN"); 1075 psF32 PSF_SN_LIM = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM"); 1076 // psF32 SATURATE = psMetadataLookupF32 (&status, metadata, "SATURATE"); 1099 1077 1100 1078 // XXX allow clump size to be scaled relative to sigmas? … … 1109 1087 psF32 sigY = tmpSrc->moments->Sy; 1110 1088 1111 // check return status value (do these exist?) 1112 bool status; 1113 psF32 RDNOISE = psMetadataLookupF32 (&status, metadata, "RDNOISE"); 1114 psF32 GAIN = psMetadataLookupF32 (&status, metadata, "GAIN"); 1115 psF32 SATURATE = psMetadataLookupF32 (&status, metadata, "SATURATE"); 1116 1117 psF32 PSF_SN_LIM = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM"); 1118 psF32 FAINT_SN_LIM = psMetadataLookupF32 (&status, metadata, "FAINT_SN_LIM"); 1119 1120 // saturated object (star or single pixel not distinguished) 1121 if (tmpSrc->moments->Peak > SATURATE) { 1122 tmpSrc->type |= PS_SOURCE_SATURATED; 1089 // calculate and save signal-to-noise estimates 1090 psF32 S = tmpSrc->moments->Sum; 1091 psF32 A = 4 * M_PI * sigX * sigY; 1092 psF32 B = tmpSrc->moments->Sky; 1093 psF32 RT = sqrt(S + (A * B) + (A * PS_SQR(RDNOISE) / sqrt(GAIN))); 1094 psF32 SN = (S * sqrt(GAIN) / RT); 1095 tmpSrc->moments->SN = SN; 1096 1097 // XXX EAM : can we use the value of SATURATE if mask is NULL? 1098 // 1099 // XXX: Must verify this region (the region argument was added to psImageCountPixelMask() 1100 // after EAM wrote this code. 1101 // 1102 psRegion tmpRegion = psRegionSet(0, tmpSrc->mask->numCols, 0, tmpSrc->mask->numRows); 1103 int Nsatpix = psImageCountPixelMask(tmpSrc->mask, tmpRegion, PSPHOT_MASK_SATURATED); 1104 1105 // saturated star (size consistent with PSF or larger) 1106 // Nsigma should be user-configured parameter 1107 bool big = (sigX > (clump.X - clump.dX)) && (sigY > (clump.Y - clump.dY)); 1108 if ((Nsatpix > 1) && big) { 1109 tmpSrc->type |= PM_SOURCE_SATSTAR; 1110 Nsatstar ++; 1111 continue; 1112 } 1113 1114 // saturated object (not a star, eg bleed trails, hot pixels) 1115 if (Nsatpix > 1) { 1116 tmpSrc->type |= PM_SOURCE_SATURATED; 1123 1117 Nsat ++; 1124 1118 continue; 1125 1119 } 1126 1120 1127 // too small to be stellar 1128 if ((sigX < (clumpX - clumpDX)) || (sigY < (clumpY - clumpDY))) { 1129 tmpSrc->type |= PS_SOURCE_DEFECT; 1121 // likely defect (too small to be stellar) (push out to 3 sigma) 1122 // low S/N objects which are small are probably stellar 1123 // only set candidate defects if 1124 if ((sigX < 0.05) || (sigY < 0.05)) { 1125 tmpSrc->type |= PM_SOURCE_DEFECT; 1130 1126 Ncr ++; 1131 1127 continue; 1132 1128 } 1133 1129 1134 // possible galaxy1135 if ((sigX > (clump X + clumpDX)) || (sigY > (clumpY + clumpDY))) {1136 tmpSrc->type |= P S_SOURCE_GALAXY;1130 // likely unsaturated galaxy (too large to be stellar) 1131 if ((sigX > (clump.X + 3*clump.dX)) || (sigY > (clump.Y + 3*clump.dY))) { 1132 tmpSrc->type |= PM_SOURCE_GALAXY; 1137 1133 Ngal ++; 1138 1134 continue; … … 1140 1136 1141 1137 // the rest are probable stellar objects 1142 psF32 S = tmpSrc->moments->Sum;1143 psF32 A = M_PI * sigX * sigY;1144 psF32 B = tmpSrc->moments->Sky;1145 psF32 RT = sqrtf(S + (A * B) + (A * PS_SQR(RDNOISE) / sqrtf(GAIN)));1146 psF32 SN = (S * sqrtf(GAIN) / RT);1147 1148 1138 starsn->data.F32[starsn->n] = SN; 1149 1139 starsn->n ++; 1150 1140 Nstar ++; 1151 1141 1152 // faint star 1153 if (SN < FAINT_SN_LIM) { 1154 tmpSrc->type |= PS_SOURCE_FAINTSTAR; 1155 Nfaint ++; 1156 continue; 1157 } 1158 1159 // PSF star 1160 if (SN > PSF_SN_LIM) { 1161 tmpSrc->type |= PS_SOURCE_PSFSTAR; 1142 // PSF star (within 1.5 sigma of clump center 1143 psF32 radius = hypot ((sigX-clump.X)/clump.dX, (sigY-clump.Y)/clump.dY); 1144 if ((SN > PSF_SN_LIM) && (radius < 1.5)) { 1145 tmpSrc->type |= PM_SOURCE_PSFSTAR; 1162 1146 Npsf ++; 1163 1147 continue; … … 1165 1149 1166 1150 // random type of star 1167 tmpSrc->type |= P S_SOURCE_OTHER;1151 tmpSrc->type |= PM_SOURCE_OTHER; 1168 1152 } 1169 1153 … … 1173 1157 stats = psVectorStats (stats, starsn, NULL, NULL, 0); 1174 1158 psLogMsg ("pmObjects", 3, "SN range: %f - %f\n", stats[0].min, stats[0].max); 1175 } 1176 1177 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar: %3d\n", Nstar); 1178 psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf: %3d\n", Npsf); 1179 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nfaint: %3d\n", Nfaint); 1180 psTrace (".pmObjects.pmSourceRoughClass", 2, "Ngal: %3d\n", Ngal); 1181 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat: %3d\n", Nsat); 1182 psTrace (".pmObjects.pmSourceRoughClass", 2, "Ncr: %3d\n", Ncr); 1183 1159 psFree (stats); 1160 psFree (starsn); 1161 } 1162 1163 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar: %3d\n", Nstar); 1164 psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf: %3d\n", Npsf); 1165 psTrace (".pmObjects.pmSourceRoughClass", 2, "Ngal: %3d\n", Ngal); 1166 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsatstar: %3d\n", Nsatstar); 1167 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat: %3d\n", Nsat); 1168 psTrace (".pmObjects.pmSourceRoughClass", 2, "Ncr: %3d\n", Ncr); 1169 1170 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1184 1171 return(rc); 1185 1172 } 1186 1173 1174 /** pmSourceDefinePixels() 1175 * 1176 * Define psImage subarrays for the source located at coordinates x,y on the 1177 * image set defined by readout. The pixels defined by this operation consist of 1178 * a square window (of full width 2Radius+1) centered on the pixel which contains 1179 * the given coordinate, in the frame of the readout. The window is defined to 1180 * have limits which are valid within the boundary of the readout image, thus if 1181 * the radius would fall outside the image pixels, the subimage is truncated to 1182 * only consist of valid pixels. If readout->mask or readout->weight are not 1183 * NULL, matching subimages are defined for those images as well. This function 1184 * fails if no valid pixels can be defined (x or y less than Radius, for 1185 * example). This function should be used to define a region of interest around a 1186 * source, including both source and sky pixels. 1187 * 1188 * XXX: must code this. 1189 * 1190 */ 1191 bool pmSourceDefinePixels( 1192 pmSource *mySource, ///< Add comment. 1193 pmReadout *readout, ///< Add comment. 1194 psF32 x, ///< Add comment. 1195 psF32 y, ///< Add comment. 1196 psF32 Radius) ///< Add comment. 1197 { 1198 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1199 psLogMsg(__func__, PS_LOG_WARN, "WARNING: pmSourceDefinePixels() has not been implemented. Returning FALSE.\n"); 1200 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1201 return(false); 1202 } 1203 1187 1204 /****************************************************************************** 1188 1205 pmSourceSetPixelsCircle(source, image, radius) 1189 1206 1190 XXX: Why boolean output? 1191 1192 XXX: Why are we checking source->moments for NULL? Should the circle be 1193 centered on the centroid or the peak? 1194 1195 XXX: The circle will have a diameter of (1+radius). This is different from 1196 the pmSourceSetLocal() function. 1207 XXX: This was replaced by DefinePixels in SDRS. Remove it. 1197 1208 *****************************************************************************/ 1198 1209 bool pmSourceSetPixelsCircle(pmSource *source, … … 1200 1211 psF32 radius) 1201 1212 { 1213 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1202 1214 PS_ASSERT_IMAGE_NON_NULL(image, false); 1203 1215 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 1204 1216 PS_ASSERT_PTR_NON_NULL(source, false); 1205 1217 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1206 //PS_ASSERT_PTR_NON_NULL(source->peak, false);1218 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1207 1219 PS_FLOAT_COMPARE(0.0, radius, false); 1208 1220 … … 1217 1229 psS32 SubImageCenterCol = source->peak->x; 1218 1230 // XXX EAM : for the circle to stay on the image 1231 // XXX EAM : EndRow is *exclusive* of pixel region (ie, last pixel + 1) 1219 1232 psS32 SubImageStartRow = PS_MAX (0, SubImageCenterRow - radiusS32); 1220 psS32 SubImageEndRow = PS_MIN (image->numRows - 1, SubImageCenterRow + radiusS32);1233 psS32 SubImageEndRow = PS_MIN (image->numRows, SubImageCenterRow + radiusS32 + 1); 1221 1234 psS32 SubImageStartCol = PS_MAX (0, SubImageCenterCol - radiusS32); 1222 psS32 SubImageEndCol = PS_MIN (image->numCols - 1, SubImageCenterCol + radiusS32); 1223 1224 // XXX EAM : this should not be needed: we can never hit this error 1225 # if (1) 1226 1227 if (SubImageStartRow < 0) { 1228 psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n", 1229 SubImageStartRow); 1230 return(false); 1231 } 1232 if (SubImageEndRow >= image->numRows) { 1233 psError(PS_ERR_UNKNOWN, true, "Sub image endRow is outside image boundaries (%d).\n", 1234 SubImageEndRow); 1235 return(false); 1236 } 1237 if (SubImageStartCol < 0) { 1238 psError(PS_ERR_UNKNOWN, true, "Sub image startCol is outside image boundaries (%d).\n", 1239 SubImageStartCol); 1240 return(false); 1241 } 1242 if (SubImageEndCol >= image->numCols) { 1243 psError(PS_ERR_UNKNOWN, true, "Sub image endCol is outside image boundaries (%d).\n", 1244 SubImageEndCol); 1245 return(false); 1246 } 1247 # endif 1235 psS32 SubImageEndCol = PS_MIN (image->numCols, SubImageCenterCol + radiusS32 + 1); 1248 1236 1249 1237 // XXX: Must recycle image. … … 1255 1243 psFree(source->pixels); 1256 1244 } 1257 // XXX: Must fix this. psImageSubset() has different parameters in latest CVS. 1258 // source->pixels = psImageSubset((psImage *) image, 1259 // SubImageStartCol, 1260 // SubImageStartRow, 1261 // SubImageEndCol, 1262 // SubImageEndRow); 1245 source->pixels = psImageSubset((psImage *) image, psRegionSet(SubImageStartCol, 1246 SubImageStartRow, 1247 SubImageEndCol, 1248 SubImageEndRow)); 1263 1249 1264 1250 // XXX: Must recycle image. … … 1268 1254 source->mask = psImageAlloc(source->pixels->numCols, 1269 1255 source->pixels->numRows, 1270 PS_TYPE_ F32);1256 PS_TYPE_U8); // XXX EAM : type was F32 1271 1257 1272 1258 // … … 1287 1273 } 1288 1274 } 1275 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 1289 1276 return(true); 1290 1277 } 1291 1278 1292 1279 /****************************************************************************** 1293 pmSourceModelGuess(source, image, model): This function allocates a new 1294 pmModel structure and stores it in the pmSource data structure specified in 1295 the argument list. The model type is specified in the argument list. The 1296 params array in that pmModel structure are allocated, and then set to the 1297 appropriate values. This function returns true if everything was successful. 1298 1299 XXX: Many of the initial parameters are set to 0.0 since I don't know what 1300 the appropiate initial guesses are. 1301 1302 XXX: The image argument is redundant. 1280 pmSourceModelGuess(source, model): This function allocates a new 1281 pmModel structure based on the given modelType specified in the argument list. 1282 The corresponding pmModelGuess function is returned, and used to 1283 supply the values of the params array in the pmModel structure. 1303 1284 1304 1285 XXX: Many parameters are based on the src->moments structure, which is in 1305 1286 image, not subImage coords. Therefore, the calls to the model evaluation 1306 1287 functions will be in image, not subImage coords. Remember this. 1307 1308 XXX: The source->models member used to be allocated here. Now I assume 1309 ->modelPSF should be allocated 1310 *****************************************************************************/ 1311 bool pmSourceModelGuess(pmSource *source, 1312 const psImage *image, 1313 pmModelType model) 1314 { 1315 PS_ASSERT_PTR_NON_NULL(source, false); 1288 *****************************************************************************/ 1289 pmModel *pmSourceModelGuess(pmSource *source, 1290 pmModelType modelType) 1291 { 1292 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1316 1293 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1317 1294 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1318 PS_ASSERT_IMAGE_NON_NULL(image, false); 1319 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 1320 if (source->modelPSF != NULL) { 1321 psLogMsg(__func__, PS_LOG_WARN, "WARNING: source->modelPSF was non-NULL; calling psFree(source->modelPSF).\n"); 1322 psFree(source->modelPSF); 1323 } 1324 if (!((model == PS_MODEL_GAUSS) || 1325 (model == PS_MODEL_PGAUSS) || 1326 (model == PS_MODEL_WAUSS) || 1327 (model == PS_MODEL_TWIST_GAUSS) || 1328 (model == PS_MODEL_SERSIC) || 1329 (model == PS_MODEL_SERSIC_CORE))) { 1330 psError(PS_ERR_UNKNOWN, true, "Undefined psModelType"); 1331 return(false); 1332 } 1333 1334 source->modelPSF = pmModelAlloc(model); 1335 1336 psVector *params = source->modelPSF->params; 1337 1338 switch (model) { 1339 case PS_MODEL_GAUSS: 1340 params->data.F32[0] = source->moments->Sky; 1341 params->data.F32[1] = source->peak->counts - source->moments->Sky; 1342 params->data.F32[2] = source->moments->x; 1343 params->data.F32[3] = source->moments->y; 1344 params->data.F32[4] = sqrt(2.0) / source->moments->Sx; 1345 params->data.F32[5] = sqrt(2.0) / source->moments->Sy; 1346 params->data.F32[6] = source->moments->Sxy; 1347 return(true); 1348 1349 case PS_MODEL_PGAUSS: 1350 params->data.F32[0] = source->moments->Sky; 1351 params->data.F32[1] = source->peak->counts - source->moments->Sky; 1352 params->data.F32[2] = source->moments->x; 1353 params->data.F32[3] = source->moments->y; 1354 params->data.F32[4] = sqrt(2.0) / source->moments->Sx; 1355 params->data.F32[5] = sqrt(2.0) / source->moments->Sy; 1356 params->data.F32[6] = source->moments->Sxy; 1357 return(true); 1358 1359 case PS_MODEL_WAUSS: 1360 params->data.F32[0] = source->moments->Sky; 1361 params->data.F32[1] = source->peak->counts - source->moments->Sky; 1362 params->data.F32[2] = source->moments->x; 1363 params->data.F32[3] = source->moments->y; 1364 params->data.F32[4] = sqrt(2.0) / source->moments->Sx; 1365 params->data.F32[5] = sqrt(2.0) / source->moments->Sy; 1366 params->data.F32[6] = source->moments->Sxy; 1367 // XXX: What are these? 1368 // source->modelPSF->params[7] = B2; 1369 // source->modelPSF->params[8] = B3; 1370 return(true); 1371 1372 // XXX EAM : I might drop this model (or rather, replace it) 1373 case PS_MODEL_TWIST_GAUSS: 1374 params->data.F32[0] = source->moments->Sky; 1375 params->data.F32[1] = source->peak->counts - source->moments->Sky; 1376 params->data.F32[2] = source->moments->x; 1377 params->data.F32[3] = source->moments->y; 1378 // XXX: What are these? 1379 // params->data.F32[4] = SxInner; 1380 // params->data.F32[5] = SyInner; 1381 // params->data.F32[6] = SxyInner; 1382 // params->data.F32[7] = SxOuter; 1383 // params->data.F32[8] = SyOuter; 1384 // params->data.F32[9] = SxyOuter; 1385 // params->data.F32[10] = N; 1386 return(true); 1387 1388 case PS_MODEL_SERSIC: 1389 params->data.F32[0] = source->moments->Sky; 1390 params->data.F32[1] = source->peak->counts - source->moments->Sky; 1391 params->data.F32[2] = source->moments->x; 1392 params->data.F32[3] = source->moments->y; 1393 params->data.F32[4] = sqrt(2.0) / source->moments->Sx; 1394 params->data.F32[5] = sqrt(2.0) / source->moments->Sy; 1395 params->data.F32[6] = source->moments->Sxy; 1396 // XXX: What are these? 1397 //params->data.F32[7] = Nexp; 1398 return(true); 1399 1400 case PS_MODEL_SERSIC_CORE: 1401 params->data.F32[0] = source->moments->Sky; 1402 params->data.F32[1] = source->peak->counts - source->moments->Sky; 1403 params->data.F32[2] = source->moments->x; 1404 params->data.F32[3] = source->moments->y; 1405 // XXX: What are these? 1406 // params->data.F32[4] SxInner; 1407 // params->data.F32[5] SyInner; 1408 // params->data.F32[6] SxyInner; 1409 // params->data.F32[7] Zd; 1410 // params->data.F32[8] SxOuter; 1411 // params->data.F32[9] SyOuter; 1412 // params->data.F32[10] = SxyOuter; 1413 // params->data.F32[11] = Nexp; 1414 return(true); 1415 1416 default: 1417 psError(PS_ERR_UNKNOWN, true, "Undefined psModelType"); 1418 return(false); 1419 } 1295 1296 pmModel *model = pmModelAlloc(modelType); 1297 1298 pmModelGuessFunc modelGuessFunc = pmModelGuessFunc_GetFunction(modelType); 1299 modelGuessFunc(model, source); 1300 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1301 return(model); 1420 1302 } 1421 1303 … … 1441 1323 testing. Try to reproduce that and debug. 1442 1324 *****************************************************************************/ 1443 static psF32 evalModel(pmSource *src, 1444 psU32 row, 1445 psU32 col) 1446 { 1447 PS_ASSERT_PTR_NON_NULL(src, false); 1448 PS_ASSERT_PTR_NON_NULL(src->modelPSF, false); 1449 PS_ASSERT_PTR_NON_NULL(src->modelPSF->params, false); 1450 1451 // XXX: The following step will not be necessary if the modelPSF->params 1452 // member is a psVector. Suggest to IfA. 1453 1454 // XXX EAM: done: modelPSF->params is now a vector 1455 psVector *params = src->modelPSF->params; 1456 1457 // 1325 1326 // XXX EAM : I have made this a public function 1327 // XXX EAM : this now uses a pmModel as the input 1328 // XXX EAM : it was using src->type to find the model, not model->type 1329 psF32 pmModelEval(pmModel *model, psImage *image, psS32 col, psS32 row) 1330 { 1331 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1332 PS_ASSERT_PTR_NON_NULL(image, false); 1333 PS_ASSERT_PTR_NON_NULL(model, false); 1334 PS_ASSERT_PTR_NON_NULL(model->params, false); 1335 1458 1336 // Allocate the x coordinate structure and convert row/col to image space. 1459 1337 // 1460 1338 psVector *x = psVectorAlloc(2, PS_TYPE_F32); 1461 x->data.F32[0] = (psF32) (col + src->pixels->col0);1462 x->data.F32[1] = (psF32) (row + src->pixels->row0);1339 x->data.F32[0] = (psF32) (col + image->col0); 1340 x->data.F32[1] = (psF32) (row + image->row0); 1463 1341 psF32 tmpF; 1464 1465 switch (src->modelPSF->type) { 1466 case PS_MODEL_GAUSS: 1467 tmpF = pmMinLM_Gauss2D(NULL, params, x); 1468 break; 1469 case PS_MODEL_PGAUSS: 1470 tmpF = pmMinLM_PsuedoGauss2D(NULL, params, x); 1471 break; 1472 case PS_MODEL_TWIST_GAUSS: 1473 tmpF = pmMinLM_TwistGauss2D(NULL, params, x); 1474 break; 1475 case PS_MODEL_WAUSS: 1476 tmpF = pmMinLM_Wauss2D(NULL, params, x); 1477 break; 1478 case PS_MODEL_SERSIC: 1479 tmpF = pmMinLM_Sersic(NULL, params, x); 1480 break; 1481 case PS_MODEL_SERSIC_CORE: 1482 tmpF = pmMinLM_SersicCore(NULL, params, x); 1483 break; 1484 default: 1485 psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType"); 1486 return(NAN); 1487 } 1342 pmModelFunc modelFunc; 1343 1344 modelFunc = pmModelFunc_GetFunction (model->type); 1345 tmpF = modelFunc (NULL, model->params, x); 1488 1346 psFree(x); 1347 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1489 1348 return(tmpF); 1490 1349 } … … 1508 1367 psU32 dir) 1509 1368 { 1369 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 1510 1370 // 1511 1371 // Convert coords to subImage space. … … 1517 1377 if (!((0 <= subCol) && (subCol < source->pixels->numCols))) { 1518 1378 psError(PS_ERR_UNKNOWN, true, "Starting column outside subImage range"); 1379 psTrace(__func__, 4, "---- %s(NAN) end ----\n", __func__); 1519 1380 return(NAN); 1520 1381 } 1521 1382 if (!((0 <= subRow) && (subRow < source->pixels->numRows))) { 1383 psTrace(__func__, 4, "---- %s(NAN) end ----\n", __func__); 1522 1384 psError(PS_ERR_UNKNOWN, true, "Starting row outside subImage range"); 1523 1385 return(NAN); 1524 1386 } 1525 1387 1526 psF32 oldValue = evalModel(source, subRow, subCol); 1388 // XXX EAM : i changed this to match pmModelEval above, but see 1389 // XXX EAM the note below in pmSourceContour 1390 psF32 oldValue = pmModelEval(source->modelFLT, source->pixels, subCol, subRow); 1527 1391 if (oldValue == level) { 1392 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 1528 1393 return(((psF32) (subCol + source->pixels->col0))); 1529 1394 } … … 1545 1410 1546 1411 while (subCol != lastColumn) { 1547 psF32 newValue = evalModel(source, subRow, subCol);1412 psF32 newValue = pmModelEval(source->modelFLT, source->pixels, subCol, subRow); 1548 1413 if (oldValue == level) { 1414 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 1549 1415 return((psF32) (subCol + source->pixels->col0)); 1550 1416 } … … 1552 1418 if ((newValue <= level) && (level <= oldValue)) { 1553 1419 // This is simple linear interpolation. 1420 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 1554 1421 return( ((psF32) (subCol + source->pixels->col0)) + ((psF32) incr) * ((level - newValue) / (oldValue - newValue)) ); 1555 1422 } … … 1557 1424 if ((oldValue <= level) && (level <= newValue)) { 1558 1425 // This is simple linear interpolation. 1426 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 1559 1427 return( ((psF32) (subCol + source->pixels->col0)) + ((psF32) incr) * ((level - oldValue) / (newValue - oldValue)) ); 1560 1428 } … … 1563 1431 } 1564 1432 1433 psTrace(__func__, 4, "---- %s(NAN) end ----\n", __func__); 1565 1434 return(NAN); 1566 1435 } … … 1576 1445 XXX: What is mode? 1577 1446 XXX: The top, bottom of the contour is not correctly determined. 1447 XXX EAM : this functions is using the model for the contour, but it should 1448 be using only the image counts 1578 1449 *****************************************************************************/ 1579 1450 psArray *pmSourceContour(pmSource *source, … … 1582 1453 pmContourType mode) 1583 1454 { 1455 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1584 1456 PS_ASSERT_PTR_NON_NULL(source, false); 1585 1457 PS_ASSERT_PTR_NON_NULL(image, false); … … 1587 1459 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1588 1460 PS_ASSERT_PTR_NON_NULL(source->pixels, false); 1589 PS_ASSERT_PTR_NON_NULL(source->modelPSF, false); 1461 PS_ASSERT_PTR_NON_NULL(source->modelFLT, false); 1462 // XXX EAM : what is the purpose of modelPSF/modelFLT? 1590 1463 1591 1464 // … … 1610 1483 psFree(xVec); 1611 1484 psFree(yVec); 1485 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1612 1486 return(NULL); 1613 1487 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); … … 1622 1496 psFree(xVec); 1623 1497 psFree(yVec); 1498 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1624 1499 return(NULL); 1625 1500 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); 1626 1501 } 1627 //printf("The intercepts are (%.2f, %.2f)\n", leftIntercept, rightIntercept);1502 psTrace(__func__, 4, "The intercepts are (%.2f, %.2f)\n", leftIntercept, rightIntercept); 1628 1503 xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept; 1629 1504 … … 1646 1521 psFree(xVec); 1647 1522 psFree(yVec); 1523 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1648 1524 return(NULL); 1649 1525 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); … … 1657 1533 psFree(xVec); 1658 1534 psFree(yVec); 1535 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1659 1536 return(NULL); 1660 1537 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); … … 1672 1549 tmpArray->data[0] = (psPtr *) yVec; 1673 1550 tmpArray->data[1] = (psPtr *) xVec; 1551 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1674 1552 return(tmpArray); 1675 1553 } 1676 1554 1677 #if 01678 static psVector *minLM_Gauss2D_Vec(psImage *deriv, psVector *params, psArray *x);1679 static psVector *minLM_PsuedoGauss2D_Vec(psImage *deriv, psVector *params, psArray *x);1680 static psVector *minLM_Wauss2D_Vec(psImage *deriv, psVector *params, psArray *x);1681 static psVector *minLM_TwistGauss2D_Vec(psImage *deriv, psVector *params, psArray *x);1682 static psVector *minLM_Sersic_Vec(psImage *deriv, psVector *params, psArray *x);1683 static psVector *minLM_SersicCore_Vec(psImage *deriv, psVector *params, psArray *x);1684 #endif1685 1686 1555 // XXX EAM : these are better starting values, but should be available from metadata? 1687 #define PM_SOURCE_FIT_MODEL_NUM_ITERATIONS 201556 #define PM_SOURCE_FIT_MODEL_NUM_ITERATIONS 15 1688 1557 #define PM_SOURCE_FIT_MODEL_TOLERANCE 0.1 1689 1558 /****************************************************************************** 1690 pmSourceFitModel(source, image): must create the appropiate arguments to the1559 pmSourceFitModel(source, model): must create the appropiate arguments to the 1691 1560 LM minimization routines for the various p_pmMinLM_XXXXXX_Vec() functions. 1692 1561 1693 1562 XXX: should there be a mask value? 1694 XXX: Probably should remove the "image" argument. 1695 *****************************************************************************/ 1696 bool pmSourceFitModel(pmSource *source, 1697 const psImage *image) 1698 { 1563 XXX EAM : fit the specified model (not necessarily the one in source) 1564 *****************************************************************************/ 1565 bool pmSourceFitModel_v5(pmSource *source, 1566 pmModel *model, 1567 const bool PSF) 1568 { 1569 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1699 1570 PS_ASSERT_PTR_NON_NULL(source, false); 1700 1571 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1701 1572 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1702 1573 PS_ASSERT_PTR_NON_NULL(source->pixels, false); 1703 PS_ASSERT_PTR_NON_NULL(source->modelPSF, false); 1704 PS_ASSERT_IMAGE_NON_NULL(image, false); 1705 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 1706 psBool rc; 1574 PS_ASSERT_PTR_NON_NULL(source->mask, false); 1575 PS_ASSERT_PTR_NON_NULL(source->weight, false); 1576 psBool fitStatus = true; 1577 psBool onPic = true; 1578 psBool rc = true; 1579 1580 // XXX EAM : is it necessary for the mask & weight to exist? the 1581 // tests below could be conditions (!NULL) 1582 1583 psVector *params = model->params; 1584 psVector *dparams = model->dparams; 1585 psVector *paramMask = NULL; 1586 1587 pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type); 1588 1589 int nParams = PSF ? params->n - 4 : params->n; 1707 1590 1708 1591 // find the number of valid pixels … … 1716 1599 } 1717 1600 } 1601 } 1602 if (count < nParams + 1) { 1603 psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n"); 1604 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 1605 return(false); 1718 1606 } 1719 1607 … … 1733 1621 x->data[tmpCnt] = (psPtr *) coord; 1734 1622 y->data.F32[tmpCnt] = source->pixels->data.F32[i][j]; 1735 1736 // XXX EAM : this is approximate: need to apply the gain and rdnoise1737 yErr->data.F32[tmpCnt] = sqrt(PS_MAX(1, source->pixels->data.F32[i][j]));1623 yErr->data.F32[tmpCnt] = sqrt (source->weight->data.F32[i][j]); 1624 // XXX EAM : note the wasted effort: we carry dY^2, take sqrt(), then 1625 // the minimization function calculates sq() 1738 1626 tmpCnt++; 1739 1627 } … … 1744 1632 PM_SOURCE_FIT_MODEL_TOLERANCE); 1745 1633 1746 psVector *params = source->modelPSF->params; 1747 1748 switch (source->modelPSF->type) { 1749 case PS_MODEL_GAUSS: 1750 rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_Gauss2D); 1751 break; 1752 case PS_MODEL_PGAUSS: 1753 rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_PsuedoGauss2D); 1754 break; 1755 case PS_MODEL_TWIST_GAUSS: 1756 rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_Wauss2D); 1757 break; 1758 case PS_MODEL_WAUSS: 1759 rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_TwistGauss2D); 1760 break; 1761 case PS_MODEL_SERSIC: 1762 rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_Sersic); 1763 break; 1764 case PS_MODEL_SERSIC_CORE: 1765 rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_SersicCore); 1766 break; 1767 default: 1768 psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType"); 1769 rc = false; 1770 } 1634 // PSF model only fits first 4 parameters, FLT model fits all 1635 if (PSF) { 1636 paramMask = psVectorAlloc (params->n, PS_TYPE_U8); 1637 for (int i = 0; i < 4; i++) { 1638 paramMask->data.U8[i] = 0; 1639 } 1640 for (int i = 4; i < paramMask->n; i++) { 1641 paramMask->data.U8[i] = 1; 1642 } 1643 } 1644 1645 // XXX EAM : covar must be F64? 1646 psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F64); 1647 1648 psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n"); 1649 fitStatus = psMinimizeLMChi2(myMin, covar, params, paramMask, x, y, yErr, modelFunc); 1650 for (int i = 0; i < dparams->n; i++) { 1651 if ((paramMask != NULL) && paramMask->data.U8[i]) 1652 continue; 1653 dparams->data.F32[i] = sqrt(covar->data.F64[i][i]); 1654 } 1655 1771 1656 // XXX EAM: we need to do something (give an error?) if rc is false 1657 // XXX EAM: psMinimizeLMChi2 does not check convergence 1658 1659 // XXX models can go insane: reject these 1660 onPic &= (params->data.F32[2] >= source->pixels->col0); 1661 onPic &= (params->data.F32[2] < source->pixels->col0 + source->pixels->numCols); 1662 onPic &= (params->data.F32[3] >= source->pixels->row0); 1663 onPic &= (params->data.F32[3] < source->pixels->row0 + source->pixels->numRows); 1664 1772 1665 // XXX EAM: save the resulting chisq, nDOF, nIter 1773 source->modelPSF->chisq = myMin->value; 1774 source->modelPSF->nDOF = y->n - params->n; 1775 source->modelPSF->nIter = myMin->iter; 1776 1666 model->chisq = myMin->value; 1667 model->nIter = myMin->iter; 1668 model->nDOF = y->n - nParams; 1669 1670 // XXX EAM get the Gauss-Newton distance for fixed model parameters 1671 if (paramMask != NULL) { 1672 psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64); 1673 psMinimizeGaussNewtonDelta (delta, params, NULL, x, y, yErr, modelFunc); 1674 for (int i = 0; i < dparams->n; i++) { 1675 if (!paramMask->data.U8[i]) 1676 continue; 1677 dparams->data.F32[i] = delta->data.F64[i]; 1678 } 1679 psFree (delta); 1680 } 1681 1682 psFree(x); 1683 psFree(y); 1684 psFree(yErr); 1685 psFree(myMin); 1686 psFree(covar); 1687 psFree(paramMask); 1688 1689 rc = (onPic && fitStatus); 1690 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1691 return(rc); 1692 } 1693 1694 // XXX EAM : new version with parameter range limits and weight enhancement 1695 bool pmSourceFitModel (pmSource *source, 1696 pmModel *model, 1697 const bool PSF) 1698 { 1699 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1700 PS_ASSERT_PTR_NON_NULL(source, false); 1701 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1702 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1703 PS_ASSERT_PTR_NON_NULL(source->pixels, false); 1704 PS_ASSERT_PTR_NON_NULL(source->mask, false); 1705 PS_ASSERT_PTR_NON_NULL(source->weight, false); 1706 1707 // XXX EAM : is it necessary for the mask & weight to exist? the 1708 // tests below could be conditions (!NULL) 1709 1710 psBool fitStatus = true; 1711 psBool onPic = true; 1712 psBool rc = true; 1713 psF32 Ro, ymodel; 1714 1715 psVector *params = model->params; 1716 psVector *dparams = model->dparams; 1717 psVector *paramMask = NULL; 1718 1719 pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type); 1720 1721 // XXX EAM : I need to use the sky value to constrain the weight model 1722 int nParams = PSF ? params->n - 4 : params->n; 1723 psF32 So = params->data.F32[0]; 1724 1725 // find the number of valid pixels 1726 // XXX EAM : this loop and the loop below could just be one pass 1727 // using the psArrayAdd and psVectorExtend functions 1728 psS32 count = 0; 1729 for (psS32 i = 0; i < source->pixels->numRows; i++) { 1730 for (psS32 j = 0; j < source->pixels->numCols; j++) { 1731 if (source->mask->data.U8[i][j] == 0) { 1732 count++; 1733 } 1734 } 1735 } 1736 if (count < nParams + 1) { 1737 psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n"); 1738 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 1739 return(false); 1740 } 1741 1742 // construct the coordinate and value entries 1743 psArray *x = psArrayAlloc(count); 1744 psVector *y = psVectorAlloc(count, PS_TYPE_F32); 1745 psVector *yErr = psVectorAlloc(count, PS_TYPE_F32); 1746 psS32 tmpCnt = 0; 1747 for (psS32 i = 0; i < source->pixels->numRows; i++) { 1748 for (psS32 j = 0; j < source->pixels->numCols; j++) { 1749 if (source->mask->data.U8[i][j] == 0) { 1750 psVector *coord = psVectorAlloc(2, PS_TYPE_F32); 1751 // XXX: Convert i/j to image space: 1752 // XXX EAM: coord order is (x,y) == (col,row) 1753 coord->data.F32[0] = (psF32) (j + source->pixels->col0); 1754 coord->data.F32[1] = (psF32) (i + source->pixels->row0); 1755 x->data[tmpCnt] = (psPtr *) coord; 1756 y->data.F32[tmpCnt] = source->pixels->data.F32[i][j]; 1757 1758 // compare observed flux to model flux to adjust weight 1759 ymodel = modelFunc (NULL, model->params, coord); 1760 1761 // this test enhances the weight based on deviation from the model flux 1762 Ro = 1.0 + fabs (y->data.F32[tmpCnt] - ymodel) / sqrt(PS_SQR(ymodel - So) + PS_SQR(So)); 1763 1764 // psMinimizeLMChi2_EAM takes wt = 1/dY^2 1765 if (source->weight->data.F32[i][j] == 0) { 1766 yErr->data.F32[tmpCnt] = 0.0; 1767 } else { 1768 yErr->data.F32[tmpCnt] = 1.0 / (source->weight->data.F32[i][j] * Ro); 1769 } 1770 tmpCnt++; 1771 } 1772 } 1773 } 1774 1775 psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, 1776 PM_SOURCE_FIT_MODEL_TOLERANCE); 1777 1778 // PSF model only fits first 4 parameters, FLT model fits all 1779 if (PSF) { 1780 paramMask = psVectorAlloc (params->n, PS_TYPE_U8); 1781 for (int i = 0; i < 4; i++) { 1782 paramMask->data.U8[i] = 0; 1783 } 1784 for (int i = 4; i < paramMask->n; i++) { 1785 paramMask->data.U8[i] = 1; 1786 } 1787 } 1788 1789 // XXX EAM : I've added three types of parameter range checks 1790 // XXX EAM : this requires my new psMinimization functions 1791 pmModelLimits modelLimits = pmModelLimits_GetFunction (model->type); 1792 psVector *beta_lim = NULL; 1793 psVector *params_min = NULL; 1794 psVector *params_max = NULL; 1795 1796 // XXX EAM : in this implementation, I pass in the limits with the covar matrix. 1797 // in the SDRS, I define a new psMinimization which will take these in 1798 psImage *covar = psImageAlloc (params->n, 3, PS_TYPE_F64); 1799 modelLimits (&beta_lim, ¶ms_min, ¶ms_max); 1800 for (int i = 0; i < params->n; i++) { 1801 covar->data.F64[0][i] = beta_lim->data.F32[i]; 1802 covar->data.F64[1][i] = params_min->data.F32[i]; 1803 covar->data.F64[2][i] = params_max->data.F32[i]; 1804 } 1805 1806 psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n"); 1807 fitStatus = psMinimizeLMChi2(myMin, covar, params, paramMask, x, y, yErr, modelFunc); 1808 for (int i = 0; i < dparams->n; i++) { 1809 if ((paramMask != NULL) && paramMask->data.U8[i]) 1810 continue; 1811 dparams->data.F32[i] = sqrt(covar->data.F64[i][i]); 1812 } 1813 1814 // XXX EAM: we need to do something (give an error?) if rc is false 1815 // XXX EAM: psMinimizeLMChi2 does not check convergence 1816 1817 // XXX models can go insane: reject these 1818 onPic &= (params->data.F32[2] >= source->pixels->col0); 1819 onPic &= (params->data.F32[2] < source->pixels->col0 + source->pixels->numCols); 1820 onPic &= (params->data.F32[3] >= source->pixels->row0); 1821 onPic &= (params->data.F32[3] < source->pixels->row0 + source->pixels->numRows); 1822 1823 // XXX EAM: save the resulting chisq, nDOF, nIter 1824 model->chisq = myMin->value; 1825 model->nIter = myMin->iter; 1826 model->nDOF = y->n - nParams; 1827 1828 // XXX EAM get the Gauss-Newton distance for fixed model parameters 1829 if (paramMask != NULL) { 1830 psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64); 1831 psMinimizeGaussNewtonDelta(delta, params, NULL, x, y, yErr, modelFunc); 1832 for (int i = 0; i < dparams->n; i++) { 1833 if (!paramMask->data.U8[i]) 1834 continue; 1835 dparams->data.F32[i] = delta->data.F64[i]; 1836 } 1837 } 1838 1839 psFree(paramMask); 1777 1840 psFree(x); 1778 1841 psFree(y); 1779 1842 psFree(myMin); 1843 1844 rc = (onPic && fitStatus); 1845 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1780 1846 return(rc); 1781 1847 } 1782 1848 1783 static bool sourceAddOrSubModel(psImage *image, 1784 pmSource *src, 1785 bool center, 1786 psS32 flag) 1787 { 1788 PS_ASSERT_PTR_NON_NULL(src, false); 1789 PS_ASSERT_PTR_NON_NULL(src->moments, false); 1790 PS_ASSERT_PTR_NON_NULL(src->peak, false); 1791 PS_ASSERT_PTR_NON_NULL(src->pixels, false); 1792 PS_ASSERT_PTR_NON_NULL(src->modelPSF, false); 1849 bool p_pmSourceAddOrSubModel(psImage *image, 1850 psImage *mask, 1851 pmModel *model, 1852 bool center, 1853 psS32 flag) 1854 { 1855 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1856 1857 PS_ASSERT_PTR_NON_NULL(model, false); 1793 1858 PS_ASSERT_IMAGE_NON_NULL(image, false); 1794 1859 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 1795 1860 1796 1861 psVector *x = psVectorAlloc(2, PS_TYPE_F32); 1797 psVector *params = src->modelPSF->params; 1798 1799 for (psS32 i = 0; i < src->pixels->numRows; i++) { 1800 for (psS32 j = 0; j < src->pixels->numCols; j++) { 1862 psVector *params = model->params; 1863 pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type); 1864 psS32 imageCol; 1865 psS32 imageRow; 1866 1867 for (psS32 i = 0; i < image->numRows; i++) { 1868 for (psS32 j = 0; j < image->numCols; j++) { 1869 if ((mask != NULL) && mask->data.U8[i][j]) 1870 continue; 1801 1871 psF32 pixelValue; 1802 1872 // XXX: Should you be adding the pixels for the entire subImage, … … 1805 1875 // Convert i/j to imace coord space: 1806 1876 // XXX: Make sure you have col/row order correct. 1807 psS32 imageRow = i + src->pixels->row0; 1808 psS32 imageCol = j + src->pixels->col0; 1877 // XXX EAM : 'center' option changes this 1878 // XXX EAM : i == numCols/2 -> x = model->params->data.F32[2] 1879 if (center) { 1880 imageCol = j - 0.5*image->numCols + model->params->data.F32[2]; 1881 imageRow = i - 0.5*image->numRows + model->params->data.F32[3]; 1882 } else { 1883 imageCol = j + image->col0; 1884 imageRow = i + image->row0; 1885 } 1809 1886 1810 1887 x->data.F32[0] = (float) imageCol; 1811 1888 x->data.F32[1] = (float) imageRow; 1812 switch (src->modelPSF->type) { 1813 case PS_MODEL_GAUSS: 1814 pixelValue = pmMinLM_Gauss2D(NULL, params, x); 1815 break; 1816 case PS_MODEL_PGAUSS: 1817 pixelValue = pmMinLM_PsuedoGauss2D(NULL, params, x); 1818 break; 1819 case PS_MODEL_TWIST_GAUSS: 1820 pixelValue = pmMinLM_TwistGauss2D(NULL, params, x); 1821 break; 1822 case PS_MODEL_WAUSS: 1823 pixelValue = pmMinLM_Wauss2D(NULL, params, x); 1824 break; 1825 case PS_MODEL_SERSIC: 1826 pixelValue = pmMinLM_Sersic(NULL, params, x); 1827 break; 1828 case PS_MODEL_SERSIC_CORE: 1829 pixelValue = pmMinLM_SersicCore(NULL, params, x); 1830 break; 1831 default: 1832 psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType"); 1833 psFree(x); 1834 return(false); 1835 } 1889 pixelValue = modelFunc (NULL, params, x); 1890 // fprintf (stderr, "%f %f %d %d %f\n", x->data.F32[0], x->data.F32[1], i, j, pixelValue); 1891 1836 1892 if (flag == 1) { 1837 1893 pixelValue = -pixelValue; … … 1841 1897 // how to use the boolean "center" flag. 1842 1898 1843 image->data.F32[i mageRow][imageCol]+= pixelValue;1899 image->data.F32[i][j]+= pixelValue; 1844 1900 } 1845 1901 } 1846 1902 psFree(x); 1903 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 1847 1904 return(true); 1848 1905 } … … 1853 1910 *****************************************************************************/ 1854 1911 bool pmSourceAddModel(psImage *image, 1855 pmSource *src, 1912 psImage *mask, 1913 pmModel *model, 1856 1914 bool center) 1857 1915 { 1858 return(sourceAddOrSubModel(image, src, center, 0)); 1916 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1917 psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, 0); 1918 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1919 return(rc); 1859 1920 } 1860 1921 … … 1862 1923 *****************************************************************************/ 1863 1924 bool pmSourceSubModel(psImage *image, 1864 pmSource *src, 1925 psImage *mask, 1926 pmModel *model, 1865 1927 bool center) 1866 1928 { 1867 return(sourceAddOrSubModel(image, src, center, 1)); 1868 } 1869 1870 1871 // XXX: Put this is psConstants.h 1872 #define PS_VECTOR_CHECK_SIZE(VEC1, N, RVAL) \ 1873 if (VEC1->n != N) { \ 1874 psError(PS_ERR_BAD_PARAMETER_SIZE, true, \ 1875 "psVector %s has size %d, should be %d.", \ 1876 #VEC1, VEC1->n, N); \ 1877 return(RVAL); \ 1878 } 1879 1880 1881 /** 1882 all of these object representation functions have the same form : func(*deriv, *params, *x) 1883 1884 the argument "x" contains a single "x,y" coordinate pair. The function computes the object 1885 model, based on the parameters in "params" at the x,y point specified by *x, and returns the value. 1886 The derivatives are also caculated and returned in the "deriv" argument. parameter error checking is 1887 skipped because speed is most important. 1888 **/ 1889 1890 /****************************************************************************** 1891 params->data.F32[0] = So; 1892 params->data.F32[1] = Zo; 1893 params->data.F32[2] = Xo; 1894 params->data.F32[3] = Yo; 1895 params->data.F32[4] = sqrt(2.0) / SigmaX; 1896 params->data.F32[5] = sqrt(2.0) / SigmaY; 1897 params->data.F32[6] = Sxy; 1898 *****************************************************************************/ 1899 float pmMinLM_Gauss2D( 1900 psVector *deriv, 1901 const psVector *params, 1902 const psVector *x) 1903 { 1904 PS_ASSERT_VECTOR_NON_NULL(params, NAN); 1905 PS_ASSERT_VECTOR_NON_NULL(x, NAN); 1906 psF32 X = x->data.F32[0] - params->data.F32[2]; 1907 psF32 Y = x->data.F32[1] - params->data.F32[3]; 1908 psF32 px = params->data.F32[4]*X; 1909 psF32 py = params->data.F32[5]*Y; 1910 psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y; 1911 psF32 r = exp(-z); 1912 psF32 q = params->data.F32[1]*r; 1913 psF32 f = q + params->data.F32[0]; 1914 1915 if (deriv != NULL) { 1916 deriv->data.F32[0] = +1.0; 1917 deriv->data.F32[1] = +r; 1918 deriv->data.F32[2] = q*(2*px*params->data.F32[4] + params->data.F32[6]*Y); 1919 deriv->data.F32[3] = q*(2*py*params->data.F32[5] + params->data.F32[6]*X); 1920 deriv->data.F32[4] = -2.0*q*px*X; 1921 deriv->data.F32[5] = -2.0*q*py*Y; 1922 deriv->data.F32[6] = -q*X*Y; 1923 } 1924 return(f); 1925 } 1926 1927 /****************************************************************************** 1928 params->data.F32[0] = So; 1929 params->data.F32[1] = Zo; 1930 params->data.F32[2] = Xo; 1931 params->data.F32[3] = Yo; 1932 params->data.F32[4] = sqrt(2) / SigmaX; 1933 params->data.F32[5] = sqrt(2) / SigmaY; 1934 params->data.F32[6] = Sxy; 1935 *****************************************************************************/ 1936 float pmMinLM_PsuedoGauss2D( 1937 psVector *deriv, 1938 const psVector *params, 1939 const psVector *x) 1940 { 1941 PS_ASSERT_VECTOR_NON_NULL(params, NAN); 1942 PS_ASSERT_VECTOR_NON_NULL(x, NAN); 1943 psF32 X = x->data.F32[0] - params->data.F32[2]; 1944 psF32 Y = x->data.F32[1] - params->data.F32[3]; 1945 psF32 px = params->data.F32[4]*X; 1946 psF32 py = params->data.F32[5]*Y; 1947 psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y; 1948 psF32 t = 1 + z + 0.5*z*z; 1949 psF32 r = 1.0 / (t*(1 + z/3)); /* exp (-Z) */ 1950 psF32 f = params->data.F32[1]*r + params->data.F32[0]; 1951 1952 if (deriv != NULL) { 1953 // note difference from a pure gaussian: q = params->data.F32[1]*r 1954 psF32 q = params->data.F32[1]*r*r*t; 1955 deriv->data.F32[0] = +1.0; 1956 deriv->data.F32[1] = +r; 1957 deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y); 1958 deriv->data.F32[3] = q*(2.0*py*params->data.F32[5] + params->data.F32[6]*X); 1959 deriv->data.F32[4] = -2.0*q*px*X; 1960 deriv->data.F32[5] = -2.0*q*py*Y; 1961 deriv->data.F32[6] = -q*X*Y; 1962 } 1963 return(f); 1964 } 1965 1966 /****************************************************************************** 1967 params->data.F32[0] = So; 1968 params->data.F32[1] = Zo; 1969 params->data.F32[2] = Xo; 1970 params->data.F32[3] = Yo; 1971 params->data.F32[4] = Sx; 1972 params->data.F32[5] = Sy; 1973 params->data.F32[6] = Sxy; 1974 params->data.F32[7] = B2; 1975 params->data.F32[8] = B3; 1976 *****************************************************************************/ 1977 float pmMinLM_Wauss2D( 1978 psVector *deriv, 1979 const psVector *params, 1980 const psVector *x) 1981 { 1982 PS_ASSERT_VECTOR_NON_NULL(params, NAN); 1983 PS_ASSERT_VECTOR_NON_NULL(x, NAN); 1984 psF32 X = x->data.F32[0] - params->data.F32[2]; 1985 psF32 Y = x->data.F32[1] - params->data.F32[2]; 1986 psF32 px = params->data.F32[4]*X; 1987 psF32 py = params->data.F32[5]*Y; 1988 psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y; 1989 psF32 t = 0.5*z*z*(1.0 + params->data.F32[8]*z/3.0); 1990 psF32 r = 1.0 / (1.0 + z + params->data.F32[7]*t); /* exp (-Z) */ 1991 psF32 f = params->data.F32[1]*r + params->data.F32[0]; 1992 1993 if (deriv != NULL) { 1994 // note difference from gaussian: q = params->data.F32[1]*r 1995 psF32 q = params->data.F32[1]*r*r*(1.0 + params->data.F32[7]*z*(1.0 + params->data.F32[8]*z/2.0)); 1996 deriv->data.F32[0] = +1.0; 1997 deriv->data.F32[1] = +r; 1998 deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y); 1999 deriv->data.F32[3] = q*(2.0*py*params->data.F32[5] + params->data.F32[6]*X); 2000 deriv->data.F32[4] = -2.0*q*px*X; 2001 deriv->data.F32[5] = -2.0*q*py*Y; 2002 deriv->data.F32[6] = -q*X*Y; 2003 deriv->data.F32[7] = -100.0*params->data.F32[1]*r*r*t; 2004 deriv->data.F32[8] = -100.0*params->data.F32[1]*r*r*params->data.F32[7]*(z*z*z)/6.0; 2005 // The values of 100 dampen the swing of params->data.F32[7,8] */ 2006 } 2007 return(f); 2008 } 2009 2010 // XXX: What should these be? 2011 #define FFACTOR 1.0 2012 #define FSCALE 1.0 2013 /****************************************************************************** 2014 params->data.F32[0] = So; 2015 params->data.F32[1] = Zo; 2016 params->data.F32[2] = Xo; 2017 params->data.F32[3] = Yo; 2018 params->data.F32[4] = SxInner; 2019 params->data.F32[5] = SyInner; 2020 params->data.F32[6] = SxyInner; 2021 params->data.F32[7] = SxOuter; 2022 params->data.F32[8] = SyOuter; 2023 params->data.F32[9] = SxyOuter; 2024 params->data.F32[10] = N; 2025 *****************************************************************************/ 2026 float pmMinLM_TwistGauss2D( 2027 psVector *deriv, 2028 const psVector *params, 2029 const psVector *x) 2030 { 2031 PS_ASSERT_VECTOR_NON_NULL(params, NAN); 2032 PS_ASSERT_VECTOR_NON_NULL(x, NAN); 2033 psF32 X = x->data.F32[0] - params->data.F32[2]; 2034 psF32 Y = x->data.F32[1] - params->data.F32[3]; 2035 psF32 px1 = params->data.F32[4]*X; 2036 psF32 py1 = params->data.F32[5]*Y; 2037 psF32 px2 = params->data.F32[7]*X; 2038 psF32 py2 = params->data.F32[8]*Y; 2039 psF32 z1 = 0.5*PS_SQR(px1) + 0.5*PS_SQR(py1) + params->data.F32[4]*X*Y; 2040 psF32 z2 = 0.5*PS_SQR(px2) + 0.5*PS_SQR(py2) + params->data.F32[9]*X*Y; 2041 psF32 r = 1.0 / (1.0 + z1 + pow(z2,params->data.F32[10])); 2042 2043 psF32 f = params->data.F32[5]*r + params->data.F32[6]; 2044 2045 if (deriv != NULL) { 2046 psF32 q1 = params->data.F32[5]*PS_SQR(r); 2047 psF32 q2 = params->data.F32[5]*PS_SQR(r)*params->data.F32[10]*pow(z2,(params->data.F32[10]-1.0)); 2048 deriv->data.F32[0] = +1.0; 2049 deriv->data.F32[1] = +r; 2050 deriv->data.F32[2] = q1*(2.0*px1*params->data.F32[4] + params->data.F32[6]*Y) + q2*(2*px2*params->data.F32[7] + params->data.F32[9]*Y); 2051 deriv->data.F32[3] = q1*(2.0*py1*params->data.F32[5] + params->data.F32[6]*X) + q2*(2*py2*params->data.F32[8] + params->data.F32[9]*X); 2052 2053 // These fudge factors impede the growth of params->data.F32[4] beyond 2054 // params->data.F32[7]. 2055 psF32 f1 = fabs(params->data.F32[7]) / fabs(params->data.F32[4]); 2056 psF32 f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0; 2057 deriv->data.F32[4] = -2.0*q1*px1*X*f2; 2058 2059 // These fudge factors impede the growth of params->data.F32[5] beyond 2060 // params->data.F32[8]. 2061 f1 = fabs(params->data.F32[8]) / fabs(params->data.F32[5]); 2062 f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0; 2063 deriv->data.F32[5] = -2.0*q1*py1*Y*f2; 2064 deriv->data.F32[6] = -q1*X*Y; 2065 deriv->data.F32[7] = -2.0*q2*px2*X; 2066 deriv->data.F32[8] = -2.0*q2*py2*Y; 2067 deriv->data.F32[9] = -q2*X*Y; 2068 deriv->data.F32[10] = -q1*log(z2); 2069 } 2070 2071 return(f); 2072 } 2073 2074 /****************************************************************************** 2075 float Sersic() 2076 params->data.F32[0] = So; 2077 params->data.F32[1] = Zo; 2078 params->data.F32[2] = Xo; 2079 params->data.F32[3] = Yo; 2080 params->data.F32[4] = Sx; 2081 params->data.F32[5] = Sy; 2082 params->data.F32[6] = Sxy; 2083 params->data.F32[7] = Nexp; 2084 *****************************************************************************/ 2085 float pmMinLM_Sersic( 2086 psVector *deriv, 2087 const psVector *params, 2088 const psVector *x) 2089 { 2090 PS_ASSERT_VECTOR_NON_NULL(params, NAN); 2091 PS_ASSERT_VECTOR_NON_NULL(x, NAN); 2092 psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet."); 2093 return(0.0); 2094 } 2095 2096 /****************************************************************************** 2097 float SersicBulge() 2098 params->data.F32[0] So; 2099 params->data.F32[1] Zo; 2100 params->data.F32[2] Xo; 2101 params->data.F32[3] Yo; 2102 params->data.F32[4] SxInner; 2103 params->data.F32[5] SyInner; 2104 params->data.F32[6] SxyInner; 2105 params->data.F32[7] Zd; 2106 params->data.F32[8] SxOuter; 2107 params->data.F32[9] SyOuter; 2108 params->data.F32[10] = SxyOuter; 2109 params->data.F32[11] = Nexp; 2110 *****************************************************************************/ 2111 float pmMinLM_SersicCore( 2112 psVector *deriv, 2113 const psVector *params, 2114 const psVector *x) 2115 { 2116 PS_ASSERT_VECTOR_NON_NULL(params, NAN); 2117 PS_ASSERT_VECTOR_NON_NULL(x, NAN); 2118 psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet."); 2119 return(0.0); 2120 } 1929 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1930 psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, 1); 1931 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1932 return(rc); 1933 } 1934 1935 -
trunk/psModules/src/objects/pmObjects.h
r5170 r5255 1 1 /** @file pmObjects.h 2 2 * 3 * This file will ... 3 * The process of finding, measuring, and classifying astronomical sources on 4 * images is one of the critical tasks of the IPP or any astronomical software 5 * system. This file will define structures and functions related to the task 6 * of source detection and measurement. The elements defined in this section 7 * are generally low-level components which can be connected together to 8 * construct a complete object measurement suite. 4 9 * 5 10 * @author GLG, MHPCC 6 11 * 7 * @version $Revision: 1. 1$ $Name: not supported by cvs2svn $8 * @date $Date: 2005- 09-28 20:43:52$12 * @version $Revision: 1.2 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2005-10-10 19:53:40 $ 9 14 * 10 15 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 19 24 #endif 20 25 21 #include <stdio.h>22 #include <math.h>26 #include <stdio.h> 27 #include <math.h> 23 28 #include "pslib.h" 29 #include "pmAstrometry.h" 30 /** 31 * In the object analysis process, we will use specific mask values to mark the 32 * image pixels. The following structure defines the relevant mask values. 33 * 34 * XXX: This is probably a bad solution: we will want to set mask values 35 * outside of the PSPHOT code. Perhaps we can set up a registered set of mask 36 * values with specific meanings that other functions can add to or define? 37 */ 38 enum { 39 PSPHOT_MASK_CLEAR = 0x00, 40 PSPHOT_MASK_INVALID = 0x01, 41 PSPHOT_MASK_SATURATED = 0x02, 42 PSPHOT_MASK_MARKED = 0x08, 43 } psphotMaskValues; 44 24 45 25 46 /** pmPeakType … … 40 61 } pmPeakType; 41 62 63 42 64 /** pmPeak data structure 65 * 66 * A source has the capacity for several types of measurements. The 67 * simplest measurement of a source is the location and flux of the peak pixel 68 * associated with the source: 43 69 * 44 70 */ … … 52 78 pmPeak; 53 79 80 54 81 /** pmMoments data structure 82 * 83 * One of the simplest measurements which can be made quickly for an object 84 * are the object moments. We specify a structure to carry the moment information 85 * for a specific source: 55 86 * 56 87 */ 57 88 typedef struct 58 89 { 59 float x; ///< X-coord of centroid. 60 float y; ///< Y-coord of centroid. 61 float Sx; ///< x-second moment. 62 float Sy; ///< y-second moment. 63 float Sxy; ///< xy cross moment. 64 float Sum; ///< Pixel sum above sky (background). 65 float Peak; ///< Peak counts above sky. 66 float Sky; ///< Sky level (background). 67 int nPixels; ///< Number of pixels used. 90 float x; ///< X-coord of centroid. 91 float y; ///< Y-coord of centroid. 92 float Sx; ///< x-second moment. 93 float Sy; ///< y-second moment. 94 float Sxy; ///< xy cross moment. 95 float Sum; ///< Pixel sum above sky (background). 96 float Peak; ///< Peak counts above sky. 97 float Sky; ///< Sky level (background). 98 float SN; ///< approx signal-to-noise 99 int nPixels; ///< Number of pixels used. 68 100 } 69 101 pmMoments; 70 102 71 /** pmModelType enumeration 72 * 73 */ 74 typedef enum { 75 PS_MODEL_GAUSS, ///< Regular 2-D Gaussian 76 PS_MODEL_PGAUSS, ///< Psuedo 2-D Gaussian 77 PS_MODEL_TWIST_GAUSS, ///< 2-D Twisted Gaussian 78 PS_MODEL_WAUSS, ///< 2-D Waussian 79 PS_MODEL_SERSIC, ///< Sersic 80 PS_MODEL_SERSIC_CORE, ///< Sersic Core 81 PS_MODEL_UNDEFINED ///< Undefined 82 } pmModelType; 83 84 /** pmModel data structure 85 * 86 */ 87 // XXX: The SDRS has the "type" member of type psS32. 103 104 /** pmPSFClump data structure 105 * 106 * A collection of object moment measurements can be used to determine 107 * approximate object classes. The key to this analysis is the location and 108 * statistics (in the second-moment plane, 109 * 110 */ 88 111 typedef struct 89 112 { 90 pmModelType type; ///< Model to be used. 91 psVector *params; ///< Paramater values. 92 psVector *dparams; ///< Parameter errors. 93 float chisq; ///< Fit chi-squared. 94 int nDOF; ///< number of degrees of freedom 95 int nIter; ///< number of iterations to reach min 113 float X; 114 float dX; 115 float Y; 116 float dY; 117 } 118 pmPSFClump; 119 120 typedef int pmModelType; 121 #define PS_MODEL_GAUSS 0 122 #define PS_MODEL_PGAUSS 1 123 #define PS_MODEL_QGAUSS 2 124 #define PS_MODEL_SGAUSS 3 125 126 127 /** pmModel data structure 128 * 129 * Every source may have two types of models: a PSF model and a FLT (floating) 130 * model. The PSF model represents the best fit of the image PSF to the specific 131 * object. In this case, the PSF-dependent parameters are specified for the 132 * object by the PSF, not by the fit. The FLT model represents the best fit of 133 * the given model to the object, with all parameters floating in the fit. 134 * 135 */ 136 typedef struct 137 { 138 pmModelType type; ///< Model to be used. 139 psVector *params; ///< Paramater values. 140 psVector *dparams; ///< Parameter errors. 141 float chisq; ///< Fit chi-squared. 142 int nDOF; ///< number of degrees of freedom 143 int nIter; ///< number of iterations to reach min 144 float radius; ///< fit radius actually used 96 145 } 97 146 pmModel; 98 147 99 148 /** pmSourceType enumeration 100 * 101 * 102 * 149 * 150 * A given source may be identified as most-likely to be one of several source 151 * types. The pmSource entry pmSourceType defines the current best-guess for this 152 * source. 153 * 154 * XXX: The values given below are currently illustrative and will require 155 * some modification as the source classification code is developed. (TBD) 156 * 103 157 */ 104 158 typedef enum { 105 PS_SOURCE_PSFSTAR, 106 PS_SOURCE_GALAXY, 107 PS_SOURCE_DEFECT, 108 PS_SOURCE_SATURATED, 109 PS_SOURCE_SATSTAR, 110 PS_SOURCE_FAINTSTAR, 111 PS_SOURCE_BRIGHTSTAR, 112 PS_SOURCE_OTHER 159 PM_SOURCE_DEFECT, ///< a cosmic-ray 160 PM_SOURCE_SATURATED, ///< random saturated pixels 161 162 PM_SOURCE_SATSTAR, ///< a saturated star 163 PM_SOURCE_PSFSTAR, ///< a PSF star 164 PM_SOURCE_GOODSTAR, ///< a good-quality star 165 166 PM_SOURCE_POOR_FIT_PSF, ///< poor quality PSF fit 167 PM_SOURCE_FAIL_FIT_PSF, ///< failed to get a good PSF fit 168 PM_SOURCE_FAINTSTAR, ///< below S/N cutoff 169 170 PM_SOURCE_GALAXY, ///< an extended object (galaxy) 171 PM_SOURCE_FAINT_GALAXY, ///< a galaxy below S/N cutoff 172 PM_SOURCE_DROP_GALAXY, ///< ? 173 PM_SOURCE_FAIL_FIT_GAL, ///< failed on the galaxy fit 174 PM_SOURCE_POOR_FIT_GAL, ///< poor quality galaxy fit 175 176 PM_SOURCE_OTHER, ///< unidentified 113 177 } pmSourceType; 114 178 … … 122 186 typedef struct 123 187 { 124 pmPeak *peak; ///< Description of peak pixel. 125 psImage *pixels; ///< Rectangular region including object pixels. 126 psImage *mask; ///< Mask which marks pixels associated with objects. 127 pmMoments *moments; ///< Basic moments measure for the object. 128 pmModel *modelPSF; ///< PSF model parameters and type 129 pmModel *modelFLT; ///< FLT model parameters and type 130 pmSourceType type; ///< Best identification of object. 188 pmPeak *peak; ///< Description of peak pixel. 189 psImage *pixels; ///< Rectangular region including object pixels. 190 psImage *weight; ///< Image variance. 191 psImage *mask; ///< Mask which marks pixels associated with objects. 192 pmMoments *moments; ///< Basic moments measure for the object. 193 pmModel *modelPSF; ///< PSF Model fit (parameters and type) 194 pmModel *modelFLT; ///< FLT (floating) Model fit (parameters and type). 195 pmSourceType type; ///< Best identification of object. 131 196 } 132 197 pmSource; 133 198 134 /** pmPeak data structure 135 * 136 * 137 * 138 */ 139 typedef struct 140 { 141 psS32 type; ///< PSF Model in use 142 psArray *params; ///< Model parameters (psPolynomial2D) 143 psF32 chisq; ///< PSF goodness statistic 144 psS32 nPSFstars; ///< number of stars used to measure PSF 145 } 146 pmPSF; 147 148 149 199 200 /** pmPeakAlloc() 201 * 202 * @return pmPeak* newly allocated pmPeak with all internal pointers set to NULL 203 */ 150 204 pmPeak *pmPeakAlloc( 151 int x, ///< Row-coordinate in image space 152 int y, ///< Col-coordinate in image space 153 float counts, ///< The value of the peak pixel 154 pmPeakType class ///< The type of peak pixel 155 ); 156 205 int x, ///< Row-coordinate in image space 206 int y, ///< Col-coordinate in image space 207 float counts, ///< The value of the peak pixel 208 pmPeakType class ///< The type of peak pixel 209 ); 210 211 212 /** pmMomentsAlloc() 213 * 214 */ 157 215 pmMoments *pmMomentsAlloc(); 216 217 218 /** pmModelAlloc() 219 * 220 */ 158 221 pmModel *pmModelAlloc(pmModelType type); 159 pmSource *pmSourceAlloc(); 160 161 /****************************************************************************** 162 pmFindVectorPeaks(vector, threshold): Find all local peaks in the given vector 163 above the given threshold. Returns a vector of type PS_TYPE_U32 containing 164 the location (x value) of all peaks. 165 *****************************************************************************/ 222 223 224 /** pmSourceAlloc() 225 * 226 */ 227 pmSource *pmSourceAlloc(); 228 229 230 /** pmFindVectorPeaks() 231 * 232 * Find all local peaks in the given vector above the given threshold. A peak 233 * is defined as any element with a value greater than its two neighbors and with 234 * a value above the threshold. Two types of special cases must be addressed. 235 * Equal value elements: If an element has the same value as the following 236 * element, it is not considered a peak. If an element has the same value as the 237 * preceding element (but not the following), then it is considered a peak. Note 238 * that this rule (arbitrarily) identifies flat regions by their trailing edge. 239 * Edge cases: At start of the vector, the element must be higher than its 240 * neighbor. At the end of the vector, the element must be higher or equal to its 241 * neighbor. These two rules again places the peak associated with a flat region 242 * which touches the image edge at the image edge. The result of this function is 243 * a vector containing the coordinates (element number) of the detected peaks 244 * (type psU32). 245 * 246 */ 166 247 psVector *pmFindVectorPeaks( 167 const psVector *vector, ///< The input vector (float) 168 float threshold ///< Threshold above which to find a peak 169 ); 170 171 /****************************************************************************** 172 pmFindImagePeaks(image, threshold): Find all local peaks in the given psImage 173 above the given threshold. Returns a psList containing the location (x/y 174 value) of all peaks. 175 *****************************************************************************/ 248 const psVector *vector, ///< The input vector (float) 249 float threshold ///< Threshold above which to find a peak 250 ); 251 252 253 /** pmFindImagePeaks() 254 * 255 * Find all local peaks in the given image above the given threshold. This 256 * function should find all row peaks using pmFindVectorPeaks, then test each row 257 * peak and exclude peaks which are not local peaks. A peak is a local peak if it 258 * has a higher value than all 8 neighbors. If the peak has the same value as its 259 * +y neighbor or +x neighbor, it is NOT a local peak. If any other neighbors 260 * have an equal value, the peak is considered a valid peak. Note two points: 261 * first, the +x neighbor condition is already enforced by pmFindVectorPeaks. 262 * Second, these rules have the effect of making flat-topped regions have single 263 * peaks at the (+x,+y) corner. When selecting the peaks, their type must also be 264 * set. The result of this function is an array of pmPeak entries. 265 * 266 */ 176 267 psArray *pmFindImagePeaks( 177 const psImage *image, ///< The input image where peaks will be found (float) 178 float threshold ///< Threshold above which to find a peak 179 ); 180 181 /****************************************************************************** 182 psCullPeaks(peaks, maxValue, valid): eliminate peaks from the psList that have 183 a peak value above the given maximum, or fall outside the valid region. 184 *****************************************************************************/ 268 const psImage *image, ///< The input image where peaks will be found (float) 269 float threshold ///< Threshold above which to find a peak 270 ); 271 272 273 /** pmCullPeaks() 274 * 275 * Eliminate peaks from the psList that have a peak value above the given 276 * maximum, or fall outside the valid region. 277 * 278 */ 185 279 psList *pmCullPeaks( 186 psList *peaks, ///< The psList of peaks to be culled 187 float maxValue, ///< Cull peaks above this value 188 const psRegion valid ///< Cull peaks otside this psRegion 189 ); 190 191 /****************************************************************************** 192 pmSource *pmSourceLocalSky(image, peak, innerRadius, outerRadius): 193 194 *****************************************************************************/ 195 pmSource *pmSourceLocalSky( 196 const psImage *image, ///< The input image (float) 197 const pmPeak *peak, ///< The peak for which the psSource struct is created. 198 psStatsOptions statsOptions, ///< The statistic used in calculating the background sky 199 float innerRadius, ///< The inner radius of the suqare annulus for calculating sky 200 float outerRadius ///< The outer radius of the suqare annulus for calculating sky 201 ); 202 203 /****************************************************************************** 204 *****************************************************************************/ 205 pmSource *pmSourceMoments( 206 pmSource *source, ///< The input pmSource for which moments will be computed 207 float radius ///< Use a circle of pixels around the peak 208 ); 209 210 /****************************************************************************** 211 pmSourceRoughClass(pmArray *source, psMetaDeta *metadata): make a guess at the 212 source classification. 213 *****************************************************************************/ 280 psList *peaks, ///< The psList of peaks to be culled 281 float maxValue, ///< Cull peaks above this value 282 const psRegion valid ///< Cull peaks otside this psRegion 283 ); 284 285 286 /** pmPeaksSubset() 287 * 288 * Create a new peaks array, removing certain types of peaks from the input 289 * array of peaks based on the given criteria. Peaks should be eliminated if they 290 * have a peak value above the given maximum value limit or if the fall outside 291 * the valid region. The result of the function is a new array with a reduced 292 * number of peaks. 293 * 294 */ 295 psArray *pmPeaksSubset( 296 psArray *peaks, ///< Add comment. 297 float maxvalue, ///< Add comment. 298 const psRegion valid ///< Add comment. 299 ); 300 301 302 /** pmSourceDefinePixels() 303 * 304 * Define psImage subarrays for the source located at coordinates x,y on the 305 * image set defined by readout. The pixels defined by this operation consist of 306 * a square window (of full width 2Radius+1) centered on the pixel which contains 307 * the given coordinate, in the frame of the readout. The window is defined to 308 * have limits which are valid within the boundary of the readout image, thus if 309 * the radius would fall outside the image pixels, the subimage is truncated to 310 * only consist of valid pixels. If readout->mask or readout->weight are not 311 * NULL, matching subimages are defined for those images as well. This function 312 * fails if no valid pixels can be defined (x or y less than Radius, for 313 * example). This function should be used to define a region of interest around a 314 * source, including both source and sky pixels. 315 * 316 * XXX: must code this. 317 * 318 */ 319 // XXX: Uncommenting the pmReadout causes compile errors. 320 bool pmSourceDefinePixels( 321 pmSource *mySource, ///< Add comment. 322 pmReadout *readout, ///< Add comment. 323 psF32 x, ///< Add comment. 324 psF32 y, ///< Add comment. 325 psF32 Radius ///< Add comment. 326 ); 327 328 329 /** pmSourceLocalSky() 330 * 331 * Measure the local sky in the vicinity of the given source. The Radius 332 * defines the square aperture in which the moments will be measured. This 333 * function assumes the source pixels have been defined, and that the value of 334 * Radius here is smaller than the value of Radius used to define the pixels. The 335 * annular region not contained within the radius defined here is used to measure 336 * the local background in the vicinity of the source. The local background 337 * measurement uses the specified statistic passed in via the statsOptions entry. 338 * This function allocates the pmMoments structure. The resulting sky is used to 339 * set the value of the pmMoments.sky element of the provided pmSource structure. 340 * 341 */ 342 bool pmSourceLocalSky( 343 pmSource *source, ///< The input image (float) 344 psStatsOptions statsOptions, ///< The statistic used in calculating the background sky 345 float Radius ///< The inner radius of the square annulus to exclude 346 ); 347 348 349 /** pmSourceMoments() 350 * 351 * Measure source moments for the given source, using the value of 352 * source.moments.sky provided as the local background value and the peak 353 * coordinates as the initial source location. The resulting moment values are 354 * applied to the source.moments entry, and the source is returned. The moments 355 * are measured within the given circular radius of the source.peak coordinates. 356 * The return value indicates the success (TRUE) of the operation. 357 * 358 */ 359 bool pmSourceMoments( 360 pmSource *source, ///< The input pmSource for which moments will be computed 361 float radius ///< Use a circle of pixels around the peak 362 ); 363 364 365 /** pmSourcePSFClump() 366 * 367 * We use the source moments to make an initial, approximate source 368 * classification, and as part of the information needed to build a PSF model for 369 * the image. As long as the PSF shape does not vary excessively across the 370 * image, the sources which are represented by a PSF (the start) will have very 371 * similar second moments. The function pmSourcePSFClump searches a collection of 372 * sources with measured moments for a group with moments which are all very 373 * similar. The function returns a pmPSFClump structure, representing the 374 * centroid and size of the clump in the sigma_x, sigma_y second-moment plane. 375 * 376 * The goal is to identify and characterize the stellar clump within the 377 * sigma_x, sigma_y second-moment plane. To do this, an image is constructed to 378 * represent this plane. The units of sigma_x and sigma_y are in image pixels. A 379 * pixel in this analysis image represents 0.1 pixels in the input image. The 380 * dimensions of the image need only be 10 pixels. The peak pixel in this image 381 * (above a threshold of half of the image maximum) is found. The coordinates of 382 * this peak pixel represent the 2D mode of the sigma_x, sigma_y distribution. 383 * The sources with sigma_x, sigma_y within 0.2 pixels of this value are then 384 * * used to calculate the median and standard deviation of the sigma_x, sigma_y 385 * values. These resulting values are returned via the pmPSFClump structure. 386 * 387 * The return value indicates the success (TRUE) of the operation. 388 * 389 * XXX: Limit the S/N of the candidate sources (part of Metadata)? (TBD). 390 * XXX: Save the clump parameters on the Metadata (TBD) 391 * 392 */ 393 pmPSFClump pmSourcePSFClump( 394 psArray *source, ///< The input pmSource 395 psMetadata *metadata ///< Contains classification parameters 396 ); 397 398 399 /** pmSourceRoughClass() 400 * 401 * Based on the specified data values, make a guess at the source 402 * classification. The sources are provides as a psArray of pmSource entries. 403 * Definable parameters needed to make the classification are provided to the 404 * routine with the psMetadata structure. The rules (in SDRS) refer to values which 405 * can be extracted from the metadata using the given keywords. Except as noted, 406 * the data type for these parameters are psF32. 407 * 408 */ 214 409 bool pmSourceRoughClass( 215 psArray *source, ///< The input pmSource 216 psMetadata *metadata ///< Contains classification parameters 217 ); 218 /****************************************************************************** 219 pmSourceSetPixelCircle(source, image, radius) 220 *****************************************************************************/ 221 bool pmSourceSetPixelsCircle( 222 pmSource *source, ///< The input pmSource 223 const psImage *image, ///< The input image (float) 224 float radius ///< The radius of the circle 225 ); 226 227 /****************************************************************************** 228 *****************************************************************************/ 229 bool pmSourceModelGuess( 230 pmSource *source, ///< The input pmSource 231 const psImage *image, ///< The input image (float) 232 pmModelType model ///< The type of model to be created. 233 ); 234 235 /****************************************************************************** 236 *****************************************************************************/ 410 psArray *source, ///< The input pmSource 411 psMetadata *metadata, ///< Contains classification parameters 412 pmPSFClump clump ///< Statistics about the PSF clump 413 ); 414 415 416 /** pmSourceModelGuess() 417 * 418 * Convert available data to an initial guess for the given model. This 419 * function allocates a pmModel entry for the pmSource structure based on the 420 * provided model selection. The method of defining the model parameter guesses 421 * are specified for each model below. The guess values are placed in the model 422 * parameters. The function returns TRUE on success or FALSE on failure. 423 * 424 */ 425 pmModel *pmSourceModelGuess( 426 pmSource *source, ///< The input pmSource 427 pmModelType model ///< The type of model to be created. 428 ); 429 430 431 /** pmContourType 432 * 433 * Only one type is defined at present. 434 * 435 */ 237 436 typedef enum { 238 437 PS_CONTOUR_CRUDE, 438 PS_CONTOUR_UNKNOWN01, 439 PS_CONTOUR_UNKNOWN02 239 440 } pmContourType; 240 441 442 443 /** pmSourceContour() 444 * 445 * Find points in a contour for the given source at the given level. If type 446 * is PM_CONTOUR_CRUDE, the contour is found by starting at the source peak, 447 * running along each pixel row until the level is crossed, then interpolating to 448 * the level coordinate for that row. This is done for each row, with the 449 * starting point determined by the midpoint of the previous row, until the 450 * starting point has a value below the contour level. The returned contour 451 * consists of two vectors giving the x and y coordinates of the contour levels. 452 * This function may be used as part of the model guess inputs. Other contour 453 * types may be specified in the future for more refined contours (TBD) 454 * 455 */ 241 456 psArray *pmSourceContour( 242 pmSource *source, ///< The input pmSource 243 const psImage *image, ///< The input image (float) (this arg should be removed) 244 float level, ///< The level of the contour 245 pmContourType mode ///< Currently this must be PS_CONTOUR_CRUDE 246 ); 247 248 /****************************************************************************** 249 *****************************************************************************/ 457 pmSource *source, ///< The input pmSource 458 const psImage *image, ///< The input image (float) (this arg should be removed) 459 float level, ///< The level of the contour 460 pmContourType mode ///< Currently this must be PS_CONTOUR_CRUDE 461 ); 462 463 464 /** pmSourceFitModel() 465 * 466 * Fit the requested model to the specified source. The starting guess for the 467 * model is given by the input source.model parameter values. The pixels of 468 * interest are specified by the source.pixelsand source.maskentries. This 469 * function calls psMinimizeLMChi2() on the image data. The function returns TRUE 470 * on success or FALSE on failure. 471 * 472 */ 250 473 bool pmSourceFitModel( 251 pmSource *source, ///< The input pmSource 252 const psImage *image ///< The input image (float) 253 ); 254 255 /****************************************************************************** 256 *****************************************************************************/ 474 pmSource *source, ///< The input pmSource 475 pmModel *model, ///< model to be fitted 476 const bool PSF ///< Treat model as PSF or FLT? 477 ); 478 479 480 /** pmModelFitStatus() 481 * 482 * This function wraps the call to the model-specific function returned by 483 * pmModelFitStatusFunc_GetFunction. The model-specific function examines the 484 * model parameters, parameter errors, Chisq, S/N, and other parameters available 485 * from model to decide if the particular fit was successful or not. 486 * 487 * XXX: Must code this. 488 * 489 */ 490 bool pmModelFitStatus( 491 pmModel *model ///< Add comment. 492 ); 493 494 495 /** pmSourceAddModel() 496 * 497 * Add the given source model flux to/from the provided image. The boolean 498 * option center selects if the source is re-centered to the image center or if 499 * it is placed at its centroid location. The boolean option sky selects if the 500 * background sky is applied (TRUE) or not. The pixel range in the target image 501 * is at most the pixel range specified by the source.pixels image. The success 502 * status is returned. 503 * 504 */ 257 505 bool pmSourceAddModel( 258 psImage *image, ///< The opuut image (float) 259 pmSource *source, ///< The input pmSource 260 bool center ///< A boolean flag that determines whether pixels are centered 261 ); 262 263 /****************************************************************************** 264 *****************************************************************************/ 506 psImage *image, ///< The output image (float) 507 psImage *mask, ///< The image pixel mask (valid == 0) 508 pmModel *model, ///< The input pmModel 509 bool center ///< A boolean flag that determines whether pixels are centered 510 ); 511 512 513 /** pmSourceSubModel() 514 * 515 * Subtract the given source model flux to/from the provided image. The 516 * boolean option center selects if the source is re-centered to the image center 517 * or if it is placed at its centroid location. The boolean option sky selects if 518 * the background sky is applied (TRUE) or not. The pixel range in the target 519 * image is at most the pixel range specified by the source.pixels image. The 520 * success status is returned. 521 * 522 */ 265 523 bool pmSourceSubModel( 266 psImage *image, ///< The output image (float) 267 pmSource *source, ///< The input pmSource 268 bool center ///< A boolean flag that determines whether pixels are centered 269 ); 270 271 /****************************************************************************** 272 XXX: Why only *x argument? 273 XXX EAM: psMinimizeLMChi2Func returns psF64, not float 274 *****************************************************************************/ 275 float pmMinLM_Gauss2D( 276 psVector *deriv, ///< A possibly-NULL structure for the output derivatives 277 const psVector *params, ///< A psVector which holds the parameters of this function 278 const psVector *x ///< A psVector which holds the row/col coordinate 279 ); 280 281 /****************************************************************************** 282 *****************************************************************************/ 283 float pmMinLM_PsuedoGauss2D( 284 psVector *deriv, ///< A possibly-NULL structure for the output derivatives 285 const psVector *params, ///< A psVector which holds the parameters of this function 286 const psVector *x ///< A psVector which holds the row/col coordinate 287 ); 288 289 /****************************************************************************** 290 *****************************************************************************/ 291 float pmMinLM_Wauss2D( 292 psVector *deriv, ///< A possibly-NULL structure for the output derivatives 293 const psVector *params, ///< A psVector which holds the parameters of this function 294 const psVector *x ///< A psVector which holds the row/col coordinate 295 ); 296 297 /****************************************************************************** 298 *****************************************************************************/ 299 float pmMinLM_TwistGauss2D( 300 psVector *deriv, ///< A possibly-NULL structure for the output derivatives 301 const psVector *params, ///< A psVector which holds the parameters of this function 302 const psVector *x ///< A psVector which holds the row/col coordinate 303 ); 304 305 /****************************************************************************** 306 *****************************************************************************/ 307 float pmMinLM_Sersic( 308 psVector *deriv, ///< A possibly-NULL structure for the output derivatives 309 const psVector *params, ///< A psVector which holds the parameters of this function 310 const psVector *x ///< A psVector which holds the row/col coordinate 311 ); 312 313 /****************************************************************************** 314 *****************************************************************************/ 315 float pmMinLM_SersicCore( 316 psVector *deriv, ///< A possibly-NULL structure for the output derivatives 317 const psVector *params, ///< A psVector which holds the parameters of this function 318 const psVector *x ///< A psVector which holds the row/col coordinate 319 ); 320 321 /****************************************************************************** 322 *****************************************************************************/ 323 float pmMinLM_PsuedoSersic( 324 psVector *deriv, ///< A possibly-NULL structure for the output derivatives 325 const psVector *params, ///< A psVector which holds the parameters of this function 326 const psVector *x ///< A psVector which holds the row/col coordinate 524 psImage *image, ///< The output image (float) 525 psImage *mask, ///< The image pixel mask (valid == 0) 526 pmModel *model, ///< The input pmModel 527 bool center ///< A boolean flag that determines whether pixels are centered 327 528 ); 328 529 … … 330 531 /** 331 532 * 332 * The object model functions are defined to allow for the flexible addition 333 * of new object models. Every object model, with parameters represented by 334 * pmModel, has an associated set of functions which provide necessary support 335 * operations. A set of abstract functions allow the programmer to select the 336 * approriate function or property for a specific named object model. 337 * 338 */ 533 * The function returns both the magnitude of the fit, defined as -2.5log(flux), 534 * where the flux is integrated under the model, theoretically from a radius of 0 535 * to infinity. In practice, we integrate the model beyond 50sigma. The aperture magnitude is 536 * defined as -2.5log(flux) , where the flux is summed for all pixels which are 537 * not excluded by the aperture mask. The model flux is calculated by calling the 538 * model-specific function provided by pmModelFlux_GetFunction. 539 * 540 * XXX: must code this. 541 * 542 */ 543 bool pmSourcePhotometry( 544 float *fitMag, ///< integrated fit magnitude 545 float *obsMag, ///< aperture flux magnitude 546 pmModel *model, ///< model used for photometry 547 psImage *image, ///< image pixels to be used 548 psImage *mask ///< mask of pixels to ignore 549 ); 550 339 551 340 552 /** 341 553 * 342 * This function is the model chi-square minimization function for this model. 343 * 344 */ 345 typedef psMinimizeLMChi2Func pmModelFunc; 346 347 348 /** 349 * 350 * This function returns the integrated flux for the given model parameters. 351 */ 352 typedef psF64 (*pmModelFlux)(const psVector *params); 353 354 355 /** 356 * 357 * This function provides the model guess parameters based on the details of 358 * the given source. 359 * 360 */ 361 typedef bool (*pmModelGuessFunc)(pmModel *model, pmSource *source); 362 363 364 /** 365 * 366 * This function constructs the PSF model for the given source based on the 367 * supplied psf and the FLT model for the object. 368 * 369 */ 370 typedef bool (*pmModelFromPSFFunc)(pmModel *modelPSF, pmModel *modelFLT, pmPSF *psf); 371 372 373 /** 374 * 375 * This function returns the radius at which the given model and parameters 376 * achieves the given flux. 377 * 378 */ 379 typedef psF64 (*pmModelRadius)(const psVector *params, double flux); 380 381 382 /** 383 * 384 * Each of the function types above has a corresponding function which returns 385 * the function given the model type: 386 * 387 */ 388 pmModelFunc pmModelFunc_GetFunction (pmModelType type); 389 pmModelFlux pmModelFlux_GetFunction (pmModelType type); 390 pmModelGuessFunc pmModelGuessFunc_GetFunction (pmModelType type); 391 pmModelFromPSFFunc pmModelFromPSFFunc_GetFunction (pmModelType type); 392 pmModelRadius pmModelRadius_GetFunction (pmModelType type); 393 psS32 pmModelParameterCount(pmModelType type); 394 psS32 pmModelSetType(char *name); 395 char *pmModelGetType(pmModelType type); 554 * This function converts the source classification into the closest available 555 * approximation to the Dophot classification scheme: 556 * 557 * PM_SOURCE_DEFECT: 8 558 * PM_SOURCE_SATURATED: 8 559 * PM_SOURCE_SATSTAR: 10 560 * PM_SOURCE_PSFSTAR: 1 561 * PM_SOURCE_GOODSTAR: 1 562 * PM_SOURCE_POOR_FIT_PSF: 7 563 * PM_SOURCE_FAIL_FIT_PSF: 4 564 * PM_SOURCE_FAINTSTAR: 4 565 * PM_SOURCE_GALAXY: 2 566 * PM_SOURCE_FAINT_GALAXY: 2 567 * PM_SOURCE_DROP_GALAXY: 2 568 * PM_SOURCE_FAIL_FIT_GAL: 2 569 * PM_SOURCE_POOR_FIT_GAL: 2 570 * PM_SOURCE_OTHER: ? 571 * 572 */ 573 int pmSourceDophotType( 574 pmSource *source ///< Add comment. 575 ); 576 577 578 /** pmSourceSextractType() 579 * 580 * This function converts the source classification into the closest available 581 * approximation to the Sextractor classification scheme. the correspondence is 582 * not yet defined (TBD) . 583 * 584 * XXX: Must code this. 585 * 586 */ 587 int pmSourceSextractType( 588 pmSource *source ///< Add comment. 589 ); 590 591 /** pmSourceFitModel_v5() 592 * 593 * Fit the requested model to the specified source. The starting guess for the 594 * model is given by the input source.model parameter values. The pixels of 595 * interest are specified by the source.pixelsand source.maskentries. This 596 * function calls psMinimizeLMChi2() on the image data. The function returns TRUE 597 * on success or FALSE on failure. 598 * 599 */ 600 bool pmSourceFitModel_v5( 601 pmSource *source, ///< The input pmSource 602 pmModel *model, ///< model to be fitted 603 const bool PSF ///< Treat model as PSF or FLT? 604 ); 605 606 607 /** pmSourceFitModel_v7() 608 * 609 * Fit the requested model to the specified source. The starting guess for the 610 * model is given by the input source.model parameter values. The pixels of 611 * interest are specified by the source.pixelsand source.maskentries. This 612 * function calls psMinimizeLMChi2() on the image data. The function returns TRUE 613 * on success or FALSE on failure. 614 * 615 */ 616 bool pmSourceFitModel_v7( 617 pmSource *source, ///< The input pmSource 618 pmModel *model, ///< model to be fitted 619 const bool PSF ///< Treat model as PSF or FLT? 620 ); 396 621 397 622 #endif -
trunk/psModules/test/objects/tst_pmObjects01.c
r5169 r5255 17 17 * 18 18 * XXX: Memory leaks are not being caught. If I allocated a psVector in these functions 19 * abd never deallocate, no error is generated. 19 * and never deallocate, no error is generated. 20 Fully Tested: 21 pmPeakAlloc() 22 pmMomentsAlloc() 23 Weakly Tested: 24 pmSourceMoments() 25 20 26 * 21 * @version $Revision: 1. 1$ $Name: not supported by cvs2svn $22 * @date $Date: 2005- 09-28 20:42:52$27 * @version $Revision: 1.2 $ $Name: not supported by cvs2svn $ 28 * @date $Date: 2005-10-10 19:53:54 $ 23 29 * 24 30 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 27 33 #include "pslib.h" 28 34 #include "pmObjects.h" 35 #include "pmModelGroup.h" 36 29 37 #define NUM_ROWS 10 30 38 #define NUM_COLS 10 … … 37 45 static int test04(void); 38 46 static int test05(void); 39 static int test06(void);47 //static int test06(void); 40 48 static int test07(void); 49 /* 41 50 static int test08(void); 42 51 static int test09(void); … … 44 53 static int test16(void); 45 54 static int test20(void); 55 */ 46 56 testDescription tests[] = { 47 57 {test00, 000, "pmObjects: structure allocators and deallocators", true, false}, … … 50 60 {test03, 001, "pmObjects: pmCullPeaks()", true, false}, 51 61 {test04, 001, "pmObjects: pmSourceLocalSky()", true, false}, 52 {test06, 001, "pmObjects: pmSourceSetPixelsCircle()", true, false},53 62 {test05, 001, "pmObjects: pmSourceMoments()", true, false}, 63 // {test06, 001, "pmObjects: pmSourceSetPixelsCircle()", true, false}, 54 64 {test07, 001, "pmObjects: pmMin()", true, false}, 55 {test08, 001, "pmObjects: pmSourceModelGuess()", true, false}, 56 {test09, 001, "pmObjects: pmSourceContour()", true, false}, 57 {test15, 001, "pmObjects: pmSourceAddModel()", true, false}, 58 {test16, 001, "pmObjects: pmSourceSubModel()", true, false}, 59 {test20, 001, "pmObjects: pmSourceSubModel()", true, false}, 65 /* 66 {test08, 001, "pmObjects: pmSourceModelGuess()", true, false}, 67 {test09, 001, "pmObjects: pmSourceContour()", true, false}, 68 {test15, 001, "pmObjects: pmSourceAddModel()", true, false}, 69 {test16, 001, "pmObjects: pmSourceSubModel()", true, false}, 70 {test20, 001, "pmObjects: pmSourceSubModel()", true, false}, 71 */ 60 72 {NULL} 61 73 }; … … 64 76 { 65 77 psLogSetFormat("HLNM"); 78 // 79 // We include the function names here in psTraceSetLevel() commands for 80 // debugging convenience. There is no guarantee that this list of functions 81 // is complete. 82 // 83 psTraceSetLevel(".", 0); 84 psTraceSetLevel("pmPeakAlloc", 0); 85 psTraceSetLevel("pmMomentsAlloc", 0); 86 psTraceSetLevel("modelFree", 0); 87 psTraceSetLevel("pmModelAlloc", 0); 88 psTraceSetLevel("sourceFree", 0); 89 psTraceSetLevel("pmSourceAlloc", 0); 90 psTraceSetLevel("pmFindVectorPeaks", 0); 91 psTraceSetLevel("getRowVectorFromImage", 0); 92 psTraceSetLevel("myListAddPeak", 0); 93 psTraceSetLevel("pmFindImagePeaks", 0); 94 psTraceSetLevel("isItInThisRegion", 0); 95 psTraceSetLevel("pmCullPeaks", 0); 96 psTraceSetLevel("pmPeaksSubset", 0); 97 psTraceSetLevel("pmSourceLocalSky", 0); 98 psTraceSetLevel("checkRadius2", 0); 99 psTraceSetLevel("pmSourceMoments", 0); 100 psTraceSetLevel("pmComparePeakAscend", 0); 101 psTraceSetLevel("pmComparePeakDescend", 0); 102 psTraceSetLevel("pmSourcePSFClump", 0); 103 psTraceSetLevel("pmSourceRoughClass", 0); 104 psTraceSetLevel("pmSourceDefinePixels", 0); 105 psTraceSetLevel("pmSourceModelGuess", 0); 106 psTraceSetLevel("pmModelEval", 0); 107 psTraceSetLevel("findValue", 0); 108 psTraceSetLevel("pmSourceContour", 0); 109 psTraceSetLevel("pmSourceFitModel_v5", 0); 110 psTraceSetLevel("pmSourceFitModel", 0); 111 psTraceSetLevel("p_pmSourceAddOrSubModel", 0); 112 psTraceSetLevel("pmSourceAddModel", 0); 113 psTraceSetLevel("pmSourceSubModel", 0); 114 66 115 return !runTestSuite(stderr, "Test Point Driver", tests, argc, argv); 67 116 } … … 116 165 (tmpMoments->nPixels != 0)) { 117 166 printf("TEST ERROR: pmMomentsAlloc() did not properly initialize the pmMoments structure.\n"); 167 printf(" tmpMoments->x is %f\n", tmpMoments->x); 168 printf(" tmpMoments->y is %f\n", tmpMoments->y); 169 printf(" tmpMoments->Sx is %f\n", tmpMoments->Sx); 170 printf(" tmpMoments->Sy is %f\n", tmpMoments->Sy); 171 printf(" tmpMoments->Sxy is %f\n", tmpMoments->Sxy); 172 printf(" tmpMoments->Sum is %f\n", tmpMoments->Sum); 173 printf(" tmpMoments->Peak is %f\n", tmpMoments->Peak); 174 printf(" tmpMoments->Sky is %f\n", tmpMoments->Sky); 175 printf(" tmp Moments->nPixels is %d\n", tmpMoments->nPixels); 118 176 testStatus = false; 119 177 } … … 121 179 psFree(tmpMoments); 122 180 123 printf("Testing pmModelAlloc(PS_MODEL_GAUSS)...\n"); 124 pmModel *tmpModel = pmModelAlloc(PS_MODEL_GAUSS); 125 if (tmpModel == NULL) { 126 printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) returned a NULL pmModel\n"); 127 testStatus = false; 128 } else { 129 if ((tmpModel->params->n != 7) || (tmpModel->dparams->n != 7)) { 130 printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) allocated an incorrect number of params (%ld, %ld)\n", 131 tmpModel->params->n, tmpModel->dparams->n); 181 182 // 183 // Loop through each type of model 184 // 185 psS32 i = 0; 186 while (0 != pmModelParameterCount(i)) { 187 printf("Testing pmModelAlloc(%s)...\n", pmModelGetType(0)); 188 pmModel *tmpModel = pmModelAlloc(i); 189 if (tmpModel == NULL) { 190 printf("TEST ERROR: pmModelAlloc(%s) returned a NULL pmModel\n", pmModelGetType(0)); 132 191 testStatus = false; 133 192 } else { 134 for (psS32 i = 0 ; i < 7 ; i++) { 135 if ((tmpModel->params->data.F32[i] != 0.0) || 136 (tmpModel->dparams->data.F32[i] != 0.0)) { 137 printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) did not ininitialize the params/dparams array to 0.0.\n"); 138 testStatus = false; 139 } 140 } 141 } 142 } 143 psFree(tmpModel); 144 145 printf("Testing pmModelAlloc(PS_MODEL_PGAUSS)...\n"); 146 tmpModel = pmModelAlloc(PS_MODEL_PGAUSS); 147 if (tmpModel == NULL) { 148 printf("TEST ERROR: pmModelAlloc(PS_MODEL_PGAUSS) returned a NULL pmModel\n"); 149 testStatus = false; 150 } else { 151 if ((tmpModel->params->n != 7) || (tmpModel->dparams->n != 7)) { 152 printf("TEST ERROR: pmModelAlloc(PS_MODEL_PGAUSS) allocated an incorrect number of params (%ld, %ld)\n", 153 tmpModel->params->n, tmpModel->dparams->n); 154 testStatus = false; 155 } else { 156 for (psS32 i = 0 ; i < 7 ; i++) { 157 if ((tmpModel->params->data.F32[i] != 0.0) || 158 (tmpModel->dparams->data.F32[i] != 0.0)) { 159 printf("TEST ERROR: pmModelAlloc(PS_MODEL_PGAUSS) did not ininitialize the params/dparams array to 0.0.\n"); 160 testStatus = false; 161 } 162 } 163 } 164 } 165 psFree(tmpModel); 166 167 printf("Testing pmModelAlloc(PS_MODEL_TWIST_GAUSS)...\n"); 168 tmpModel = pmModelAlloc(PS_MODEL_TWIST_GAUSS); 169 if (tmpModel == NULL) { 170 printf("TEST ERROR: pmModelAlloc(PS_MODEL_TWIST_GAUSS) returned a NULL pmModel\n"); 171 testStatus = false; 172 } else { 173 if ((tmpModel->params->n != 11) || (tmpModel->dparams->n != 11)) { 174 printf("TEST ERROR: pmModelAlloc(PS_MODEL_TWIST_GAUSS) allocated an incorrect number of params (%ld, %ld)\n", 175 tmpModel->params->n, tmpModel->dparams->n); 176 testStatus = false; 177 } else { 178 for (psS32 i = 0 ; i < 11 ; i++) { 179 if ((tmpModel->params->data.F32[i] != 0.0) || 180 (tmpModel->dparams->data.F32[i] != 0.0)) { 181 printf("TEST ERROR: pmModelAlloc(PS_MODEL_TWIST_GAUSS) did not ininitialize the params/dparams array to 0.0.\n"); 182 testStatus = false; 183 } 184 } 185 } 186 } 187 psFree(tmpModel); 188 189 printf("Testing pmModelAlloc(PS_MODEL_WAUSS)...\n"); 190 tmpModel = pmModelAlloc(PS_MODEL_WAUSS); 191 if (tmpModel == NULL) { 192 printf("TEST ERROR: pmModelAlloc(PS_MODEL_WAUSS) returned a NULL pmModel\n"); 193 testStatus = false; 194 } else { 195 if ((tmpModel->params->n != 9) || (tmpModel->dparams->n != 9)) { 196 printf("TEST ERROR: pmModelAlloc(PS_MODEL_WAUSS) allocated an incorrect number of params (%ld, %ld)\n", 197 tmpModel->params->n, tmpModel->dparams->n); 198 testStatus = false; 199 } else { 200 for (psS32 i = 0 ; i < 9 ; i++) { 201 if ((tmpModel->params->data.F32[i] != 0.0) || 202 (tmpModel->dparams->data.F32[i] != 0.0)) { 203 printf("TEST ERROR: pmModelAlloc(PS_MODEL_WAUSS) did not ininitialize the params/dparams array to 0.0.\n"); 204 testStatus = false; 205 } 206 } 207 } 208 } 209 psFree(tmpModel); 210 211 printf("Testing pmModelAlloc(PS_MODEL_SERSIC)...\n"); 212 tmpModel = pmModelAlloc(PS_MODEL_SERSIC); 213 if (tmpModel == NULL) { 214 printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC) returned a NULL pmModel\n"); 215 testStatus = false; 216 } else { 217 if ((tmpModel->params->n != 8) || (tmpModel->dparams->n != 8)) { 218 printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC) allocated an incorrect number of params (%ld, %ld)\n", 219 tmpModel->params->n, tmpModel->dparams->n); 220 testStatus = false; 221 } else { 222 for (psS32 i = 0 ; i < 8 ; i++) { 223 if ((tmpModel->params->data.F32[i] != 0.0) || 224 (tmpModel->dparams->data.F32[i] != 0.0)) { 225 printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC) did not ininitialize the params/dparams array to 0.0.\n"); 226 testStatus = false; 227 } 228 } 229 } 230 } 231 psFree(tmpModel); 232 233 printf("Testing pmModelAlloc(PS_MODEL_SERSIC_CORE)...\n"); 234 tmpModel = pmModelAlloc(PS_MODEL_SERSIC_CORE); 235 if (tmpModel == NULL) { 236 printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC_CORE) returned a NULL pmModel\n"); 237 testStatus = false; 238 } else { 239 if ((tmpModel->params->n != 12) || (tmpModel->dparams->n != 12)) { 240 printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC_CORE) allocated an incorrect number of params (%ld, %ld)\n", 241 tmpModel->params->n, tmpModel->dparams->n); 242 testStatus = false; 243 } else { 244 for (psS32 i = 0 ; i < 12 ; i++) { 245 if ((tmpModel->params->data.F32[i] != 0.0) || 246 (tmpModel->dparams->data.F32[i] != 0.0)) { 247 printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC_CORE) did not ininitialize the params/dparams array to 0.0.\n"); 248 testStatus = false; 249 } 250 } 251 } 252 } 253 psFree(tmpModel); 193 194 /* XXX: Should we test that the members were set correctly? 195 if ((tmpModel->params->n != 7) || (tmpModel->dparams->n != 7)) { 196 printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) allocated an incorrect number of params (%ld, %ld)\n", 197 tmpModel->params->n, tmpModel->dparams->n); 198 testStatus = false; 199 } else { 200 for (psS32 i = 0 ; i < 7 ; i++) { 201 if ((tmpModel->params->data.F32[i] != 0.0) || 202 (tmpModel->dparams->data.F32[i] != 0.0)) { 203 printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) did not ininitialize the params/dparams array to 0.0.\n"); 204 testStatus = false; 205 } 206 } 207 } 208 */ 209 } 210 psFree(tmpModel); 211 i++; 212 } 213 254 214 255 215 pmSource *tmpSource = pmSourceAlloc(); … … 775 735 } 776 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 777 803 #define TST04_NUM_ROWS 100 778 804 #define TST04_NUM_COLS 100 … … 792 818 bool testStatus = true; 793 819 psImage *imgData = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_F32); 794 for (psS32 i = 0 ; i < imgData->numRows; i++) {795 for (psS32 j = 0 ; j < imgData->numCols; j++) {796 imgData->data.F32[i][j] = TST04_SKY;797 }798 }820 psImageInit(imgData, TST04_SKY); 821 psImage *imgMask = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_U8); 822 psImageInit(imgMask, 0); 823 // psImage *imgMaskS8 = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_S8); 824 // psImageInit(imgMaskS8, 0); 799 825 psImage *imgDataF64 = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_F64); 800 for (psS32 i = 0 ; i < imgDataF64->numRows; i++) { 801 for (psS32 j = 0 ; j < imgDataF64->numCols; j++) { 802 imgDataF64->data.F64[i][j] = 0.0; 803 } 804 } 805 pmSource *rc = NULL; 826 psImageInit(imgDataF64, 0.0); 806 827 pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST04_NUM_ROWS / 2), 807 828 (psF32) (TST04_NUM_COLS / 2), 808 829 200.0, 809 830 PM_PEAK_LONE); 810 811 printf("----------------------------------------------------------------------------------\n"); 812 printf("Calling pmSourceLocalSky with NULL psImage. Should generate error and return NULL.\n"); 813 rc = pmSourceLocalSky(NULL, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0); 814 if (rc != NULL) { 815 printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n"); 816 psFree(rc); 817 testStatus = false; 818 } 819 820 printf("----------------------------------------------------------------------------------\n"); 821 printf("Calling pmSourceLocalSky with wrong-type psImage. Should generate error and return NULL.\n"); 822 rc = pmSourceLocalSky(imgDataF64, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0); 823 if (rc != NULL) { 824 printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n"); 825 psFree(rc); 826 testStatus = false; 827 } 828 829 printf("----------------------------------------------------------------------------------\n"); 830 printf("Calling pmSourceLocalSky with NULL pmPeak. Should generate error and return NULL.\n"); 831 rc = pmSourceLocalSky(imgData, NULL, PS_STAT_SAMPLE_MEAN, 10.0, 20.0); 832 if (rc != NULL) { 833 printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n"); 834 psFree(rc); 835 testStatus = false; 836 } 837 838 printf("----------------------------------------------------------------------------------\n"); 839 printf("Calling pmSourceLocalSky with innerRadius<0.0. Should generate error and return NULL.\n"); 840 rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, -10.0, 20.0); 841 if (rc != NULL) { 842 printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n"); 843 psFree(rc); 844 testStatus = false; 845 } 846 847 printf("----------------------------------------------------------------------------------\n"); 848 printf("Calling pmSourceLocalSky with innerRadius>outerRadius. Should generate error and return NULL.\n"); 849 rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 5.0); 850 if (rc != NULL) { 851 printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n"); 852 psFree(rc); 853 testStatus = false; 854 } 855 /* XXX: This is commented out since the EAM modification no longer generated NULLS for these tests. 856 printf("----------------------------------------------------------------------------------\n"); 857 printf("Calling pmSourceLocalSky with subImage startRow < 0. Should generate error and return NULL.\n"); 858 tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2); 859 tmpPeak->y = (psF32) (TST04_NUM_COLS / 2); 860 tmpPeak->y = 1; 861 rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0); 862 if (rc != NULL) { 863 printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n"); 864 psFree(rc); 865 testStatus = false; 866 } 867 printf("----------------------------------------------------------------------------------\n"); 868 printf("Calling pmSourceLocalSky with subImage endRow > numRows. Should generate error and return NULL.\n"); 869 tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2); 870 tmpPeak->y = (psF32) (TST04_NUM_COLS / 2); 871 tmpPeak->y = TST04_NUM_ROWS; 872 rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0); 873 if (rc != NULL) { 874 printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n"); 875 psFree(rc); 876 testStatus = false; 877 } 878 printf("----------------------------------------------------------------------------------\n"); 879 printf("Calling pmSourceLocalSky with subImage startCol < 0. Should generate error and return NULL.\n"); 880 tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2); 881 tmpPeak->y = (psF32) (TST04_NUM_COLS / 2); 882 tmpPeak->x = 1; 883 rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0); 884 if (rc != NULL) { 885 printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n"); 886 psFree(rc); 887 testStatus = false; 888 } 889 printf("----------------------------------------------------------------------------------\n"); 890 printf("Calling pmSourceLocalSky with subImage endCol > numCols. Should generate error and return NULL.\n"); 891 tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2); 892 tmpPeak->y = (psF32) (TST04_NUM_COLS / 2); 893 tmpPeak->x = TST04_NUM_COLS; 894 rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, (psF32) TST04_INNER_RADIUS, (psF32) TST04_OUTER_RADIUS); 895 if (rc != NULL) { 896 printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n"); 897 psFree(rc); 898 testStatus = false; 899 } 900 */ 831 pmSource *tmpSource = pmSourceAlloc(); 832 tmpSource->pixels = imgData; 833 tmpSource->mask = imgMask; 834 tmpSource->peak = tmpPeak; 835 836 printf("----------------------------------------------------------------------------------\n"); 837 printf("Calling pmSourceLocalSky with NULL tmpSource. Should generate error and return FALSE.\n"); 838 bool rc = pmSourceLocalSky(NULL, PS_STAT_SAMPLE_MEAN, 10.0); 839 if (rc != false) { 840 printf("TEST ERROR: pmSourceLocalSky() returned a non-FALSE pmSource.\n"); 841 testStatus = false; 842 } 843 844 printf("----------------------------------------------------------------------------------\n"); 845 printf("Calling pmSourceLocalSky with Radius<0.0. Should generate error and return FALSE.\n"); 846 rc = pmSourceLocalSky(tmpSource, PS_STAT_SAMPLE_MEAN, -10.0); 847 if (rc != false) { 848 printf("TEST ERROR: pmSourceLocalSky() returned a non-FALSE pmSource.\n"); 849 testStatus = false; 850 } 901 851 902 852 // … … 908 858 tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2); 909 859 tmpPeak->y = (psF32) (TST04_NUM_COLS / 2); 910 rc = pmSourceLocalSky(imgData, 911 tmpPeak, 912 PS_STAT_SAMPLE_MEAN, 913 (psF32) TST04_INNER_RADIUS, 914 (psF32) TST04_OUTER_RADIUS); 915 916 if (rc == NULL) { 917 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n"); 860 rc = pmSourceLocalSky(tmpSource, PS_STAT_SAMPLE_MEAN, 10.0); 861 862 if (rc == false) { 863 printf("TEST ERROR: pmSourceLocalSky() returned a FALSE pmSource.\n"); 918 864 testStatus = false; 919 865 } else { 920 if ( rc->peak == NULL) {866 if (tmpSource->peak == NULL) { 921 867 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource->peak.\n"); 922 868 testStatus = false; 923 869 } else { 924 if (rc->peak->x != tmpPeak->x) { 925 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->x was %d, should have been %d.\n", rc->peak->x, tmpPeak->x); 870 if (tmpSource->peak->x != tmpPeak->x) { 871 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->x was %d, should have been %d.\n", 872 tmpSource->peak->x, tmpPeak->x); 926 873 testStatus = false; 927 874 } 928 875 929 if (rc->peak->y != tmpPeak->y) { 930 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->y was %d, should have been %d.\n", rc->peak->y, tmpPeak->y); 876 if (tmpSource->peak->y != tmpPeak->y) { 877 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->y was %d, should have been %d.\n", 878 tmpSource->peak->y, tmpPeak->y); 931 879 testStatus = false; 932 880 } 933 881 934 if (rc->peak->counts != tmpPeak->counts) { 935 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->counts was %f, should have been %f.\n", rc->peak->counts, tmpPeak->counts); 882 if (tmpSource->peak->counts != tmpPeak->counts) { 883 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->counts was %f, should have been %f.\n", 884 tmpSource->peak->counts, tmpPeak->counts); 936 885 testStatus = false; 937 886 } 938 887 939 if (rc->peak->class != tmpPeak->class) { 940 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->class was %d, should have been %d.\n", rc->peak->class, tmpPeak->class); 888 if (tmpSource->peak->class != tmpPeak->class) { 889 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->class was %d, should have been %d.\n", 890 tmpSource->peak->class, tmpPeak->class); 941 891 testStatus = false; 942 892 } 943 893 } 944 894 945 if ( rc->pixels == NULL) {946 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels was NULL.\n");895 if (tmpSource->moments == NULL) { 896 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource->moments.\n"); 947 897 testStatus = false; 948 898 } else { 949 if (rc->pixels->numRows != (2 * TST04_OUTER_RADIUS)) { 950 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->numRows was %d, should have been %d.\n", 951 rc->pixels->numRows, (2 * TST04_OUTER_RADIUS)); 899 if (tmpSource->moments->Sky != TST04_SKY) { 900 printf("TEST ERROR: pmSourceLocalSky() pmSource->moments->Sky was %f, should have been %f.\n", tmpSource->moments->Sky, TST04_SKY); 952 901 testStatus = false; 953 902 } 954 955 if (rc->pixels->numCols != (2 * TST04_OUTER_RADIUS)) { 956 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->numCols was %d, should have been %d.\n", 957 rc->pixels->numCols, (2 * TST04_OUTER_RADIUS)); 958 testStatus = false; 959 } 960 961 if (rc->pixels->col0 != (tmpPeak->x - TST04_OUTER_RADIUS)) { 962 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->col0 was %d, should have been %d.\n", 963 rc->pixels->col0, (tmpPeak->x - TST04_OUTER_RADIUS)); 964 testStatus = false; 965 } 966 967 if (rc->pixels->row0 != (tmpPeak->y - TST04_OUTER_RADIUS)) { 968 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->row0 was %d, should have been %d.\n", 969 rc->pixels->row0, (tmpPeak->y - TST04_OUTER_RADIUS)); 970 testStatus = false; 971 } 972 973 if (rc->pixels->type.type != PS_TYPE_F32) { 974 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->type was %d, should have been %d.\n", 975 rc->pixels->type.type, PS_TYPE_F32); 976 testStatus = false; 977 } 978 979 // XXX: Test the rc->pixels-> row/col offsets. 980 // XXX: Test that the pixels corresponds to the source image pixels. 981 } 982 983 if (rc->mask == NULL) { 984 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask was NULL.\n"); 985 testStatus = false; 986 } else { 987 if (rc->mask->numRows != (2 * TST04_OUTER_RADIUS)) { 988 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask->numRows was %d, should have been %d.\n", 989 rc->mask->numRows, (2 * TST04_OUTER_RADIUS)); 990 testStatus = false; 991 } 992 993 if (rc->mask->numCols != (2 * TST04_OUTER_RADIUS)) { 994 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask->numCols was %d, should have been %d.\n", 995 rc->mask->numCols, (2 * TST04_OUTER_RADIUS)); 996 testStatus = false; 997 } 998 999 if (rc->mask->type.type != PS_TYPE_U8) { 1000 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask->type was %d, should have been %d.\n", 1001 rc->mask->type.type, PS_TYPE_U8); 1002 testStatus = false; 1003 } 1004 1005 // XXX: Test the rc->mask-> row/col offsets. 1006 // XXX: Test that the correct pixels were masked, not merely the number of masked pixels. 1007 psS32 unmaskedPixels = 0; 1008 psS32 maskedPixels = 0; 1009 1010 for (psS32 row = 0 ; row < rc->mask->numRows; row++) { 1011 for (psS32 col = 0 ; col < rc->mask->numCols; col++) { 1012 if (rc->mask->data.U8[row][col] == 0) { 1013 unmaskedPixels++; 1014 } else { 1015 maskedPixels++; 1016 } 1017 } 1018 } 1019 if (maskedPixels != PS_SQR(2*(TST04_INNER_RADIUS-1))) { 1020 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask had %d masked pixels, should have been %d.\n", 1021 maskedPixels, PS_SQR(2*(TST04_INNER_RADIUS-1))); 1022 testStatus = false; 1023 } 1024 if (unmaskedPixels != (PS_SQR(2*TST04_OUTER_RADIUS) - PS_SQR(2*(TST04_INNER_RADIUS-1)))) { 1025 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask had %d masked pixels, should have been %d.\n", 1026 unmaskedPixels, (PS_SQR(2*TST04_OUTER_RADIUS) - PS_SQR(2*(TST04_INNER_RADIUS-1)))); 1027 testStatus = false; 1028 } 1029 } 1030 1031 if (rc->moments == NULL) { 1032 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource->moments.\n"); 1033 testStatus = false; 1034 } else { 1035 if (rc->moments->Sky != TST04_SKY) { 1036 printf("TEST ERROR: pmSourceLocalSky() pmSource->moments->Sky was %f, should have been %f.\n", rc->moments->Sky, TST04_SKY); 1037 testStatus = false; 1038 } 1039 } 1040 } 1041 1042 printf("----------------------------------------------------------------------------------\n"); 1043 psFree(rc); 1044 psFree(imgData); 1045 psFree(imgDataF64); 1046 return(testStatus); 1047 } 1048 1049 #define TST06_NUM_ROWS 100 1050 #define TST06_NUM_COLS 100 1051 #define TST06_SKY 20.0 1052 #define TST06_INNER_RADIUS 3 1053 #define TST06_OUTER_RADIUS 5 1054 /****************************************************************************** 1055 test06(): We first test pmSourceLocalSky() with various NULL and unallowable 1056 input parameters. 1057 1058 XXX: Should we produce tests with boundary numbers for the inner/outer radius? 1059 1060 XXX: Call this with varying sizes for the image. 1061 *****************************************************************************/ 1062 int test06( void ) 1063 { 1064 bool testStatus = true; 1065 pmSource *tmpSource = NULL; 1066 bool rc = false; 1067 // Create the image used in this test. 1068 psImage *imgData = psImageAlloc(TST06_NUM_COLS, TST06_NUM_ROWS, PS_TYPE_F32); 1069 for (psS32 i = 0 ; i < imgData->numRows; i++) { 1070 for (psS32 j = 0 ; j < imgData->numCols; j++) { 1071 imgData->data.F32[i][j] = TST06_SKY; 1072 } 1073 } 1074 psImage *imgDataF64 = psImageAlloc(TST06_NUM_COLS, TST06_NUM_ROWS, PS_TYPE_F64); 1075 for (psS32 i = 0 ; i < imgDataF64->numRows; i++) { 1076 for (psS32 j = 0 ; j < imgDataF64->numCols; j++) { 1077 imgDataF64->data.F64[i][j] = 0.0; 1078 } 1079 } 1080 1081 // 1082 // Create a pmPeak with the center pixel set to the peak. 1083 // 1084 pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST06_NUM_ROWS / 2), 1085 (psF32) (TST06_NUM_COLS / 2), 1086 200.0, 1087 PM_PEAK_LONE); 1088 1089 tmpSource = pmSourceLocalSky(imgData, 1090 tmpPeak, 1091 PS_STAT_SAMPLE_MEAN, 1092 (psF32) TST06_INNER_RADIUS, 1093 (psF32) TST06_OUTER_RADIUS); 1094 if (tmpSource == NULL) { 1095 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n"); 1096 psFree(imgData); 1097 psFree(imgDataF64); 1098 psFree(tmpSource); 1099 testStatus = false; 1100 return(testStatus); 1101 } 1102 1103 printf("----------------------------------------------------------------------------------\n"); 1104 printf("Calling pmSourceSetPixelsCircle with NULL pmSource. Should generate error and return NULL.\n"); 1105 rc = pmSourceSetPixelsCircle(NULL, imgData, 10.0); 1106 if (rc == true) { 1107 printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n"); 1108 testStatus = false; 1109 } 1110 // XXX: test with pmSource->peaks NULL 1111 1112 printf("----------------------------------------------------------------------------------\n"); 1113 printf("Calling pmSourceSetPixelsCircle with NULL psImage. Should generate error and return NULL.\n"); 1114 rc = pmSourceSetPixelsCircle(tmpSource, NULL, 10.0); 1115 if (rc == true) { 1116 printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n"); 1117 testStatus = false; 1118 } 1119 1120 printf("----------------------------------------------------------------------------------\n"); 1121 printf("Calling pmSourceSetPixelsCircle with wrong type psImage. Should generate error and return NULL.\n"); 1122 rc = pmSourceSetPixelsCircle(tmpSource, imgDataF64, 10.0); 1123 if (rc == true) { 1124 printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n"); 1125 testStatus = false; 1126 } 1127 1128 printf("----------------------------------------------------------------------------------\n"); 1129 printf("Calling pmSourceSetPixelsCircle with radius < 0.0. Should generate error and return NULL.\n"); 1130 rc = pmSourceSetPixelsCircle(tmpSource, imgData, -10.0); 1131 if (rc == true) { 1132 printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n"); 1133 testStatus = false; 1134 } 1135 1136 /* XXX: Commented away since the EAM mods no longer produced errors. 1137 printf("----------------------------------------------------------------------------------\n"); 1138 printf("Calling pmSourceSetPixelsCircle with subImage startCol < 0. Should generate error and return NULL.\n"); 1139 tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2); 1140 tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2); 1141 tmpSource->peak->x = 1; 1142 rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0); 1143 if (rc == true) { 1144 printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n"); 1145 testStatus = false; 1146 } 1147 1148 printf("----------------------------------------------------------------------------------\n"); 1149 printf("Calling pmSourceSetPixelsCircle with subImage endCol > numCols. Should generate error and return NULL.\n"); 1150 tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2); 1151 tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2); 1152 tmpSource->peak->x = TST06_NUM_COLS; 1153 rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0); 1154 if (rc == true) { 1155 printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n"); 1156 testStatus = false; 1157 } 1158 1159 printf("----------------------------------------------------------------------------------\n"); 1160 printf("Calling pmSourceSetPixelsCircle with subImage startRow < 0. Should generate error and return NULL.\n"); 1161 tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2); 1162 tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2); 1163 tmpSource->peak->y = 1; 1164 rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0); 1165 if (rc == true) { 1166 printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n"); 1167 testStatus = false; 1168 } 1169 1170 printf("----------------------------------------------------------------------------------\n"); 1171 printf("Calling pmSourceSetPixelsCircle with subImage endRow > numRows. Should generate error and return NULL.\n"); 1172 tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2); 1173 tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2); 1174 tmpSource->peak->y = TST06_NUM_ROWS; 1175 rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0); 1176 if (rc == true) { 1177 printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n"); 1178 testStatus = false; 1179 } 1180 */ 1181 printf("----------------------------------------------------------------------------------\n"); 1182 printf("Calling pmSourceSetPixelsCircle with valid data.\n"); 1183 tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2); 1184 tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2); 1185 rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0); 1186 1187 if (rc == false) { 1188 printf("TEST ERROR: pmSourceSetPixelsCircle() returned FALSE.\n"); 1189 testStatus = false; 1190 } else { 1191 // XXX: Test correctness of the various psSetPixelsCircle members. 1192 } 1193 1194 printf("----------------------------------------------------------------------------------\n"); 903 } 904 } 905 906 printf("----------------------------------------------------------------------------------\n"); 907 psFree(tmpSource); 1195 908 // psFree(imgData); 1196 909 // psFree(imgDataF64); 1197 psFree(tmpSource); 910 // psFree(imgMask); 911 // psFree(imgMaskS8); 1198 912 return(testStatus); 1199 1200 913 } 1201 914 … … 1218 931 { 1219 932 bool testStatus = true; 1220 pmSource *tmpSource = NULL;1221 pmSource *rc = NULL;1222 // Create the image used in this test.1223 psImage *imgData = psImageAlloc(TST05_NUM_COLS, TST05_NUM_ROWS, PS_TYPE_F32);1224 for (psS32 i = 0 ; i < imgData->numRows; i++) {1225 for (psS32 j = 0 ; j < imgData->numCols; j++) {1226 imgData->data.F32[i][j] = TST05_SKY;1227 }1228 }1229 1230 //1231 // Create a pmPeak with the center pixel set to the peak.1232 //1233 pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST05_NUM_ROWS / 2),1234 (psF32) (TST05_NUM_COLS / 2),1235 200.0,1236 PM_PEAK_LONE);1237 1238 tmpSource = pmSourceLocalSky(imgData,1239 tmpPeak,1240 PS_STAT_SAMPLE_MEAN,1241 (psF32) TST05_INNER_RADIUS,1242 (psF32) TST05_OUTER_RADIUS);1243 if (tmpSource == NULL) {1244 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");1245 psFree(tmpSource);1246 testStatus = false;1247 return(testStatus);1248 }1249 1250 printf("----------------------------------------------------------------------------------\n");1251 printf("Calling pmSourceMoments with NULL pmSource. Should generate error and return NULL.\n");1252 rc = pmSourceMoments(NULL, 10.0);1253 if (rc != NULL) {1254 printf("TEST ERROR: pmSourceMoments() returned a non-NULL pmSource.\n");1255 testStatus = false;1256 }1257 // XXX: test with pmSource->peaks NULL1258 // XXX: test with pmSource->pixels NULL1259 // XXX: test with pmSource->mask NULL1260 1261 printf("----------------------------------------------------------------------------------\n");1262 printf("Calling pmSourceMoments with radius < 0.0. Should generate error and return NULL.\n");1263 rc = pmSourceMoments(tmpSource, -10.0);1264 if (rc != NULL) {1265 printf("TEST ERROR: pmSourceMoments() returned a non-NULL pmSource.\n");1266 testStatus = false;1267 }1268 1269 printf("----------------------------------------------------------------------------------\n");1270 psFree(tmpSource);1271 return(testStatus);1272 1273 }1274 1275 /******************************************************************************1276 test07(): We first test the various psMinLM_... routines with various NULL and1277 unallowable input parameters.1278 1279 XXX: We don't verify the numbers. Must do this.1280 *****************************************************************************/1281 int test07( void )1282 {1283 bool testStatus = true;1284 psF32 rc;1285 psVector *deriv = psVectorAlloc(7, PS_TYPE_F32);1286 psVector *params = psVectorAlloc(7, PS_TYPE_F32);1287 psVector *x = psVectorAlloc(2, PS_TYPE_F32);1288 for (psS32 i = 0 ; i < 7 ; i++) {1289 deriv->data.F32[i] = 1.0;1290 params->data.F32[i] = 1.0;1291 }1292 1293 printf("----------------------------------------------------------------------------------\n");1294 printf("Calling pmMinLM_Gauss2D with NULL deriv vector. Should not generate error.\n");1295 rc = pmMinLM_Gauss2D(NULL, params, x);1296 if (isnan(rc)) {1297 printf("TEST ERROR: pmMinLM_Gauss2D() returned a NAN psF32.\n");1298 testStatus = false;1299 }1300 printf("----------------------------------------------------------------------------------\n");1301 printf("Calling pmMinLM_Gauss2D with NULL params vector. Should generate error and return NAN.\n");1302 rc = pmMinLM_Gauss2D(deriv, NULL, x);1303 if (!isnan(rc)) {1304 printf("TEST ERROR: pmMinLM_Gauss2D() returned a non-NAN psF32 (%f).\n", rc);1305 testStatus = false;1306 }1307 printf("----------------------------------------------------------------------------------\n");1308 printf("Calling pmMinLM_Gauss2D with NULL x vector. Should generate error and return NAN.\n");1309 rc = pmMinLM_Gauss2D(deriv, params, NULL);1310 if (!isnan(rc)) {1311 printf("TEST ERROR: pmMinLM_Gauss2D() returned a non-NAN psF32 (%f).\n", rc);1312 testStatus = false;1313 }1314 psFree(deriv);1315 psFree(params);1316 1317 deriv = psVectorAlloc(7, PS_TYPE_F32);1318 params = psVectorAlloc(7, PS_TYPE_F32);1319 for (psS32 i = 0 ; i < 7 ; i++) {1320 deriv->data.F32[i] = 1.0;1321 params->data.F32[i] = 1.0;1322 }1323 printf("----------------------------------------------------------------------------------\n");1324 printf("Calling pmMinLM_PsuedoGauss2D with NULL deriv vector. Should not generate error.\n");1325 rc = pmMinLM_PsuedoGauss2D(NULL, params, x);1326 if (isnan(rc)) {1327 printf("TEST ERROR: pmMinLM_PsuedoGauss2D() returned a NAN psF32.\n");1328 testStatus = false;1329 }1330 printf("----------------------------------------------------------------------------------\n");1331 printf("Calling pmMinLM_PsuedoGauss2D with NULL params vector. Should generate error and return NAN.\n");1332 rc = pmMinLM_PsuedoGauss2D(deriv, NULL, x);1333 if (!isnan(rc)) {1334 printf("TEST ERROR: pmMinLM_PsuedoGauss2D() returned a non-NAN psF32 (%f).\n", rc);1335 testStatus = false;1336 }1337 printf("----------------------------------------------------------------------------------\n");1338 printf("Calling pmMinLM_PsuedoGauss2D with NULL x vector. Should generate error and return NAN.\n");1339 rc = pmMinLM_PsuedoGauss2D(deriv, params, NULL);1340 if (!isnan(rc)) {1341 printf("TEST ERROR: pmMinLM_PsuedoGauss2D() returned a non-NAN psF32 (%f).\n", rc);1342 testStatus = false;1343 }1344 psFree(deriv);1345 psFree(params);1346 1347 1348 deriv = psVectorAlloc(9, PS_TYPE_F32);1349 params = psVectorAlloc(9, PS_TYPE_F32);1350 for (psS32 i = 0 ; i < 9 ; i++) {1351 deriv->data.F32[i] = 1.0;1352 params->data.F32[i] = 1.0;1353 }1354 printf("----------------------------------------------------------------------------------\n");1355 printf("Calling pmMinLM_Wauss2D with NULL deriv vector. Should not generate error.\n");1356 rc = pmMinLM_Wauss2D(NULL, params, x);1357 if (isnan(rc)) {1358 printf("TEST ERROR: pmMinLM_Wauss2D() returned a NAN psF32.\n");1359 testStatus = false;1360 }1361 printf("----------------------------------------------------------------------------------\n");1362 printf("Calling pmMinLM_Wauss2D with NULL params vector. Should generate error and return NAN.\n");1363 rc = pmMinLM_Wauss2D(deriv, NULL, x);1364 if (!isnan(rc)) {1365 printf("TEST ERROR: pmMinLM_Wauss2D() returned a non-NAN psF32 (%f).\n", rc);1366 testStatus = false;1367 }1368 printf("----------------------------------------------------------------------------------\n");1369 printf("Calling pmMinLM_Wauss2D with NULL x vector. Should generate error and return NAN.\n");1370 rc = pmMinLM_Wauss2D(deriv, params, NULL);1371 if (!isnan(rc)) {1372 printf("TEST ERROR: pmMinLM_Wauss2D() returned a non-NAN psF32 (%f).\n", rc);1373 testStatus = false;1374 }1375 psFree(deriv);1376 psFree(params);1377 1378 deriv = psVectorAlloc(11, PS_TYPE_F32);1379 params = psVectorAlloc(11, PS_TYPE_F32);1380 for (psS32 i = 0 ; i < 11 ; i++) {1381 deriv->data.F32[i] = 1.0;1382 params->data.F32[i] = 1.0;1383 }1384 printf("----------------------------------------------------------------------------------\n");1385 printf("Calling pmMinLM_TwistGauss2D with NULL deriv vector. Should not generate error.\n");1386 rc = pmMinLM_TwistGauss2D(NULL, params, x);1387 if (isnan(rc)) {1388 printf("TEST ERROR: pmMinLM_TwistGauss2D() returned a NAN psF32.\n");1389 testStatus = false;1390 }1391 printf("----------------------------------------------------------------------------------\n");1392 printf("Calling pmMinLM_TwistGauss2D with NULL params vector. Should generate error and return NAN.\n");1393 rc = pmMinLM_TwistGauss2D(deriv, NULL, x);1394 if (!isnan(rc)) {1395 printf("TEST ERROR: pmMinLM_TwistGauss2D() returned a non-NAN psF32 (%f).\n", rc);1396 testStatus = false;1397 }1398 printf("----------------------------------------------------------------------------------\n");1399 printf("Calling pmMinLM_TwistGauss2D with NULL x vector. Should generate error and return NAN.\n");1400 rc = pmMinLM_TwistGauss2D(deriv, params, NULL);1401 if (!isnan(rc)) {1402 printf("TEST ERROR: pmMinLM_TwistGauss2D() returned a non-NAN psF32 (%f).\n", rc);1403 testStatus = false;1404 }1405 psFree(deriv);1406 psFree(params);1407 1408 deriv = psVectorAlloc(8, PS_TYPE_F32);1409 params = psVectorAlloc(8, PS_TYPE_F32);1410 for (psS32 i = 0 ; i < 8 ; i++) {1411 deriv->data.F32[i] = 1.0;1412 params->data.F32[i] = 1.0;1413 }1414 printf("----------------------------------------------------------------------------------\n");1415 printf("Calling pmMinLM_Sersic with NULL deriv vector. Should not generate error.\n");1416 rc = pmMinLM_Sersic(NULL, params, x);1417 if (isnan(rc)) {1418 printf("TEST ERROR: pmMinLM_Sersic() returned a NAN psF32.\n");1419 testStatus = false;1420 }1421 printf("----------------------------------------------------------------------------------\n");1422 printf("Calling pmMinLM_Sersic with NULL params vector. Should generate error and return NAN.\n");1423 rc = pmMinLM_Sersic(deriv, NULL, x);1424 if (!isnan(rc)) {1425 printf("TEST ERROR: pmMinLM_Sersic() returned a non-NAN psF32 (%f).\n", rc);1426 testStatus = false;1427 }1428 printf("----------------------------------------------------------------------------------\n");1429 printf("Calling pmMinLM_Sersic with NULL x vector. Should generate error and return NAN.\n");1430 rc = pmMinLM_Sersic(deriv, params, NULL);1431 if (!isnan(rc)) {1432 printf("TEST ERROR: pmMinLM_Sersic() returned a non-NAN psF32 (%f).\n", rc);1433 testStatus = false;1434 }1435 psFree(deriv);1436 psFree(params);1437 1438 deriv = psVectorAlloc(12, PS_TYPE_F32);1439 params = psVectorAlloc(12, PS_TYPE_F32);1440 for (psS32 i = 0 ; i < 12 ; i++) {1441 deriv->data.F32[i] = 1.0;1442 params->data.F32[i] = 1.0;1443 }1444 printf("----------------------------------------------------------------------------------\n");1445 printf("Calling pmMinLM_SersicCore with NULL deriv vector. Should not generate error.\n");1446 rc = pmMinLM_SersicCore(NULL, params, x);1447 if (isnan(rc)) {1448 printf("TEST ERROR: pmMinLM_SersicCore() returned a NAN psF32.\n");1449 testStatus = false;1450 }1451 printf("----------------------------------------------------------------------------------\n");1452 printf("Calling pmMinLM_SersicCore with NULL params vector. Should generate error and return NAN.\n");1453 rc = pmMinLM_SersicCore(deriv, NULL, x);1454 if (!isnan(rc)) {1455 printf("TEST ERROR: pmMinLM_SersicCore() returned a non-NAN psF32 (%f).\n", rc);1456 testStatus = false;1457 }1458 printf("----------------------------------------------------------------------------------\n");1459 printf("Calling pmMinLM_SersicCore with NULL x vector. Should generate error and return NAN.\n");1460 rc = pmMinLM_SersicCore(deriv, params, NULL);1461 if (!isnan(rc)) {1462 printf("TEST ERROR: pmMinLM_SersicCore() returned a non-NAN psF32 (%f).\n", rc);1463 testStatus = false;1464 }1465 1466 psFree(deriv);1467 psFree(params);1468 psFree(x);1469 return(testStatus);1470 }1471 1472 /******************************************************************************1473 test08(): We first test pmSourceModelGuess() with various NULL and unallowable1474 input parameters.1475 1476 XXX: We don't verify the numbers.1477 *****************************************************************************/1478 int test08( void )1479 {1480 bool testStatus = true;1481 933 psImage *imgData = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_F32); 1482 for (psS32 i = 0 ; i < imgData->numRows; i++) { 1483 for (psS32 j = 0 ; j < imgData->numCols; j++) { 1484 imgData->data.F32[i][j] = TST04_SKY; 1485 } 1486 } 1487 pmSource *mySrc = NULL; 1488 bool rc = false; 934 psImageInit(imgData, TST04_SKY); 935 psImage *imgMask = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_U8); 936 psImageInit(imgMask, 0); 1489 937 pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST04_NUM_ROWS / 2), 1490 938 (psF32) (TST04_NUM_COLS / 2), 1491 939 200.0, 1492 940 PM_PEAK_LONE); 1493 1494 printf("Calling pmSourceLocalSky with valid data.\n"); 1495 tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2); 1496 tmpPeak->y = (psF32) (TST04_NUM_COLS / 2); 1497 mySrc = pmSourceLocalSky(imgData, 1498 tmpPeak, 1499 PS_STAT_SAMPLE_MEAN, 1500 (psF32) TST04_INNER_RADIUS, 1501 (psF32) TST04_OUTER_RADIUS); 1502 1503 if (mySrc == NULL) { 1504 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n"); 1505 testStatus = false; 1506 } 1507 1508 printf("----------------------------------------------------------------------------------\n"); 1509 printf("Calling pmSourceModelGuess with NULL pmSource. Should generate error, return FALSE.\n"); 1510 rc = pmSourceModelGuess(NULL, imgData, PS_MODEL_GAUSS); 1511 if (rc == true) { 1512 printf("TEST ERROR: pmSourceModelGuess() returned TRUE.\n"); 1513 testStatus = false; 1514 } 1515 1516 printf("----------------------------------------------------------------------------------\n"); 1517 printf("Calling pmSourceModelGuess with NULL psImage. Should generate error, return FALSE.\n"); 1518 rc = pmSourceModelGuess(mySrc, NULL, PS_MODEL_GAUSS); 1519 if (rc == true) { 1520 printf("TEST ERROR: pmSourceModelGuess() returned TRUE.\n"); 1521 testStatus = false; 1522 } 1523 1524 printf("----------------------------------------------------------------------------------\n"); 1525 printf("Calling pmSourceModelGuess with bad model type. Should generate error, return FALSE.\n"); 1526 rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_UNDEFINED); 1527 if (rc == true) { 1528 printf("TEST ERROR: pmSourceModelGuess() returned TRUE.\n"); 1529 testStatus = false; 1530 } 1531 1532 printf("----------------------------------------------------------------------------------\n"); 1533 printf("Calling pmSourceModelGuess with PS_MODEL_GAUSS\n"); 1534 rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_GAUSS); 1535 if (rc != true) { 1536 printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n"); 1537 testStatus = false; 1538 } 1539 1540 printf("----------------------------------------------------------------------------------\n"); 1541 printf("Calling pmSourceModelGuess with PS_MODEL_PGAUSS\n"); 1542 rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_PGAUSS); 1543 if (rc != true) { 1544 printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n"); 1545 testStatus = false; 1546 } 1547 1548 printf("----------------------------------------------------------------------------------\n"); 1549 printf("Calling pmSourceModelGuess with PS_MODEL_TWIST_GAUSS\n"); 1550 rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_TWIST_GAUSS); 1551 if (rc != true) { 1552 printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n"); 1553 testStatus = false; 1554 } 1555 1556 printf("----------------------------------------------------------------------------------\n"); 1557 printf("Calling pmSourceModelGuess with PS_MODEL_WAUSS\n"); 1558 rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_WAUSS); 1559 if (rc != true) { 1560 printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n"); 1561 testStatus = false; 1562 } 1563 1564 printf("----------------------------------------------------------------------------------\n"); 1565 printf("Calling pmSourceModelGuess with PS_MODEL_SERSIC\n"); 1566 rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_SERSIC); 1567 if (rc != true) { 1568 printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n"); 1569 testStatus = false; 1570 } 1571 1572 printf("----------------------------------------------------------------------------------\n"); 1573 printf("Calling pmSourceModelGuess with PS_MODEL_SERSIC_CORE\n"); 1574 rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_SERSIC_CORE); 1575 if (rc != true) { 1576 printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n"); 1577 testStatus = false; 1578 } 1579 1580 psFree(mySrc); 1581 // psFree(tmpPeak); 1582 psFree(imgData); 941 pmSource *tmpSource = pmSourceAlloc(); 942 tmpSource->pixels = imgData; 943 tmpSource->mask = imgMask; 944 tmpSource->peak = tmpPeak; 945 psBool rc = pmSourceLocalSky(tmpSource, PS_STAT_SAMPLE_MEAN, 10.0); 946 947 if (rc == false) { 948 printf("TEST ERROR: pmSourceLocalSky() returned a FALSE pmSource.\n"); 949 testStatus = false; 950 } 951 952 printf("----------------------------------------------------------------------------------\n"); 953 printf("Calling pmSourceMoments with NULL pmSource. Should generate error and return FALSE.\n"); 954 rc = pmSourceMoments(NULL, 10.0); 955 if (rc != false) { 956 printf("TEST ERROR: pmSourceMoments() returned TRUE.\n"); 957 testStatus = false; 958 } 959 // XXX: test with pmSource->peaks NULL 960 // XXX: test with pmSource->pixels NULL 961 // XXX: test with pmSource->mask NULL 962 963 printf("----------------------------------------------------------------------------------\n"); 964 printf("Calling pmSourceMoments with radius < 0.0. Should generate error and return FALSE.\n"); 965 rc = pmSourceMoments(tmpSource, -10.0); 966 if (rc != false) { 967 printf("TEST ERROR: pmSourceMoments() returned TRUE.\n"); 968 testStatus = false; 969 } 970 971 printf("----------------------------------------------------------------------------------\n"); 972 psFree(tmpSource); 1583 973 return(testStatus); 974 1584 975 } 1585 976 1586 1587 #define TST09_NUM_ROWS 701588 #define TST09_NUM_COLS 701589 #define TST09_SKY 5.01590 #define TST09_INNER_RADIUS 31591 #define TST09_OUTER_RADIUS 101592 #define LEVEL (TST09_SKY + 10.0)1593 /******************************************************************************1594 test09(): We first test pmSourceContour() with various NULL and unallowable1595 input parameters.1596 1597 XXX: We don't verify the numbers.1598 *****************************************************************************/1599 int test09( void )1600 {1601 bool testStatus = true;1602 psImage *imgData = psImageAlloc(TST09_NUM_COLS, TST09_NUM_ROWS, PS_TYPE_F32);1603 for (psS32 i = 0 ; i < imgData->numRows; i++) {1604 for (psS32 j = 0 ; j < imgData->numCols; j++) {1605 imgData->data.F32[i][j] = TST09_SKY;1606 }1607 }1608 pmSource *mySrc = NULL;1609 psArray *rc = NULL;1610 1611 pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST09_NUM_ROWS / 2),1612 (psF32) (TST09_NUM_COLS / 2),1613 200.0,1614 PM_PEAK_LONE);1615 1616 printf("Calling pmSourceLocalSky with valid data.\n");1617 tmpPeak->x = (psF32) (TST09_NUM_ROWS / 2);1618 tmpPeak->y = (psF32) (TST09_NUM_COLS / 2);1619 mySrc = pmSourceLocalSky(imgData,1620 tmpPeak,1621 PS_STAT_SAMPLE_MEAN,1622 (psF32) TST09_INNER_RADIUS,1623 (psF32) TST09_OUTER_RADIUS);1624 1625 if (mySrc == NULL) {1626 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");1627 testStatus = false;1628 }1629 1630 bool rcBool = pmSourceModelGuess(mySrc, imgData, PS_MODEL_GAUSS);1631 if (rcBool != true) {1632 printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n");1633 testStatus = false;1634 }1635 1636 printf("----------------------------------------------------------------------------------\n");1637 printf("Calling pmSourceContour with NULL pmSource . Should generate error, return NULL.\n");1638 rc = pmSourceContour(NULL, imgData, LEVEL, PS_CONTOUR_CRUDE);1639 if (rc != NULL) {1640 printf("TEST ERROR: pmSourceContour() returned non-NULL.\n");1641 testStatus = false;1642 psFree(rc);1643 }1644 1645 printf("----------------------------------------------------------------------------------\n");1646 printf("Calling pmSourceContour with NULL psImage . Should generate error, return NULL.\n");1647 rc = pmSourceContour(mySrc, NULL, LEVEL, PS_CONTOUR_CRUDE);1648 if (rc != NULL) {1649 printf("TEST ERROR: pmSourceContour() returned non-NULL.\n");1650 testStatus = false;1651 psFree(rc);1652 }1653 1654 //1655 // XXX: pmSourceContour() has a problem with contour tops/bottoms.1656 // Must correct this.1657 //1658 if (0) {1659 printf("----------------------------------------------------------------------------------\n");1660 printf("Calling pmSourceContour with acceptable data.\n");1661 printf("NOTE: must figure out the parameters for this test to be meaningful.\n");1662 mySrc->modelPSF->params->data.F32[0] = TST09_SKY;1663 mySrc->modelPSF->params->data.F32[1] = 15.0;1664 mySrc->modelPSF->params->data.F32[2] = (psF32) (TST09_NUM_ROWS / 2);1665 mySrc->modelPSF->params->data.F32[3] = (psF32) (TST09_NUM_COLS / 2);1666 mySrc->modelPSF->params->data.F32[4] = 2.0;1667 mySrc->modelPSF->params->data.F32[5] = 2.0;1668 mySrc->modelPSF->params->data.F32[6] = 2.0;1669 rc = pmSourceContour(mySrc, imgData, LEVEL, PS_CONTOUR_CRUDE);1670 if (rc == NULL) {1671 printf("TEST ERROR: pmSourceContour() returned NULL.\n");1672 testStatus = false;1673 } else {1674 psFree(rc);1675 }1676 }1677 1678 psFree(mySrc);1679 psFree(imgData);1680 // XXX: This psFree() causes an error. Why?1681 //psFree(tmpPeak);1682 return(testStatus);1683 }1684 1685 #define TST15_NUM_ROWS 1001686 #define TST15_NUM_COLS 1001687 #define TST15_SKY 10.01688 #define TST15_INNER_RADIUS 31689 #define TST15_OUTER_RADIUS 51690 /******************************************************************************1691 test15(): We first test pmSourceAddModel() with various NULL and unallowable1692 input parameters.1693 1694 XXX: We don't verify the numbers.1695 *****************************************************************************/1696 int test15( void )1697 {1698 bool testStatus = true;1699 psImage *imgData = psImageAlloc(TST15_NUM_COLS, TST15_NUM_ROWS, PS_TYPE_F32);1700 for (psS32 i = 0 ; i < imgData->numRows; i++) {1701 for (psS32 j = 0 ; j < imgData->numCols; j++) {1702 imgData->data.F32[i][j] = TST15_SKY;1703 }1704 }1705 pmSource *mySrc = NULL;1706 psBool rc = false;1707 1708 pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST15_NUM_ROWS / 2),1709 (psF32) (TST15_NUM_COLS / 2),1710 200.0,1711 PM_PEAK_LONE);1712 1713 printf("Calling pmSourceLocalSky with valid data.\n");1714 tmpPeak->x = (psF32) (TST15_NUM_ROWS / 2);1715 tmpPeak->y = (psF32) (TST15_NUM_COLS / 2);1716 mySrc = pmSourceLocalSky(imgData,1717 tmpPeak,1718 PS_STAT_SAMPLE_MEAN,1719 (psF32) TST15_INNER_RADIUS,1720 (psF32) TST15_OUTER_RADIUS);1721 1722 if (mySrc == NULL) {1723 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");1724 testStatus = false;1725 }1726 1727 mySrc->modelPSF = pmModelAlloc(PS_MODEL_GAUSS);1728 mySrc->modelPSF->params->data.F32[0] = 5.0;1729 mySrc->modelPSF->params->data.F32[1] = 70.0;1730 mySrc->modelPSF->params->data.F32[2] = (psF32) (TST15_NUM_ROWS / 2);1731 mySrc->modelPSF->params->data.F32[3] = (psF32) (TST15_NUM_COLS / 2);1732 mySrc->modelPSF->params->data.F32[4] = 1.0;1733 mySrc->modelPSF->params->data.F32[5] = 1.0;1734 mySrc->modelPSF->params->data.F32[6] = 2.0;1735 1736 printf("----------------------------------------------------------------------------------\n");1737 printf("Calling pmSourceAddModel with NULL psImage. Should generate error, return FALSE.\n");1738 rc = pmSourceAddModel(NULL, mySrc, true);1739 if (rc == true) {1740 printf("TEST ERROR: pmSourceAddModel() returned TRUE.\n");1741 testStatus = false;1742 }1743 1744 printf("----------------------------------------------------------------------------------\n");1745 printf("Calling pmSourceAddModel with NULL psSrc. Should generate error, return FALSE.\n");1746 rc = pmSourceAddModel(imgData, NULL, true);1747 if (rc == true) {1748 printf("TEST ERROR: pmSourceAddModel() returned TRUE.\n");1749 testStatus = false;1750 }1751 1752 printf("----------------------------------------------------------------------------------\n");1753 printf("Calling pmSourceAddModel with acceptable data.\n");1754 rc = pmSourceAddModel(imgData, mySrc, true);1755 if (rc != true) {1756 printf("TEST ERROR: pmSourceAddModel() returned FALSE.\n");1757 testStatus = false;1758 }1759 1760 psFree(mySrc);1761 psFree(imgData);1762 return(testStatus);1763 }1764 1765 #define TST16_NUM_ROWS 1001766 #define TST16_NUM_COLS 1001767 #define TST16_SKY 10.01768 #define TST16_INNER_RADIUS 31769 #define TST16_OUTER_RADIUS 51770 /******************************************************************************1771 test16(): We first test pmSourceSubModel() with various NULL and unallowable1772 input parameters.1773 1774 XXX: We don't verify the numbers.1775 *****************************************************************************/1776 int test16( void )1777 {1778 bool testStatus = true;1779 psImage *imgData = psImageAlloc(TST16_NUM_COLS, TST16_NUM_ROWS, PS_TYPE_F32);1780 for (psS32 i = 0 ; i < imgData->numRows; i++) {1781 for (psS32 j = 0 ; j < imgData->numCols; j++) {1782 imgData->data.F32[i][j] = TST16_SKY;1783 }1784 }1785 pmSource *mySrc = NULL;1786 psBool rc = false;1787 1788 pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST16_NUM_ROWS / 2),1789 (psF32) (TST16_NUM_COLS / 2),1790 200.0,1791 PM_PEAK_LONE);1792 1793 printf("Calling pmSourceLocalSky with valid data.\n");1794 tmpPeak->x = (psF32) (TST16_NUM_ROWS / 2);1795 tmpPeak->y = (psF32) (TST16_NUM_COLS / 2);1796 mySrc = pmSourceLocalSky(imgData,1797 tmpPeak,1798 PS_STAT_SAMPLE_MEAN,1799 (psF32) TST16_INNER_RADIUS,1800 (psF32) TST16_OUTER_RADIUS);1801 1802 if (mySrc == NULL) {1803 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");1804 testStatus = false;1805 }1806 1807 mySrc->modelPSF = pmModelAlloc(PS_MODEL_GAUSS);1808 mySrc->modelPSF->params->data.F32[0] = 5.0;1809 mySrc->modelPSF->params->data.F32[1] = 70.0;1810 mySrc->modelPSF->params->data.F32[2] = (psF32) (TST16_NUM_ROWS / 2);1811 mySrc->modelPSF->params->data.F32[3] = (psF32) (TST16_NUM_COLS / 2);1812 mySrc->modelPSF->params->data.F32[4] = 1.0;1813 mySrc->modelPSF->params->data.F32[5] = 1.0;1814 mySrc->modelPSF->params->data.F32[6] = 2.0;1815 1816 printf("----------------------------------------------------------------------------------\n");1817 printf("Calling pmSourceSubModel with NULL psImage. Should generate error, return FALSE.\n");1818 rc = pmSourceSubModel(NULL, mySrc, true);1819 if (rc == true) {1820 printf("TEST ERROR: pmSourceSubModel() returned TRUE.\n");1821 testStatus = false;1822 }1823 1824 printf("----------------------------------------------------------------------------------\n");1825 printf("Calling pmSourceSubModel with NULL psSrc. Should generate error, return FALSE.\n");1826 rc = pmSourceSubModel(imgData, NULL, true);1827 if (rc == true) {1828 printf("TEST ERROR: pmSourceSubModel() returned TRUE.\n");1829 testStatus = false;1830 }1831 1832 printf("----------------------------------------------------------------------------------\n");1833 printf("Calling pmSourceSubModel with acceptable data.\n");1834 rc = pmSourceSubModel(imgData, mySrc, true);1835 if (rc != true) {1836 printf("TEST ERROR: pmSourceSubModel() returned FALSE.\n");1837 testStatus = false;1838 }1839 1840 psFree(mySrc);1841 psFree(imgData);1842 return(testStatus);1843 }1844 1845 #define TST20_NUM_ROWS 1001846 #define TST20_NUM_COLS 1001847 #define TST20_SKY 10.01848 #define TST20_INNER_RADIUS 31849 #define TST20_OUTER_RADIUS 51850 /******************************************************************************1851 test20(): We first test pmSourceSubModel() with various NULL and unallowable1852 input parameters.1853 1854 XXX: We don't verify the numbers.1855 *****************************************************************************/1856 int test20( void )1857 {1858 bool testStatus = true;1859 psImage *imgData = psImageAlloc(TST20_NUM_COLS, TST20_NUM_ROWS, PS_TYPE_F32);1860 for (psS32 i = 0 ; i < imgData->numRows; i++) {1861 for (psS32 j = 0 ; j < imgData->numCols; j++) {1862 imgData->data.F32[i][j] = TST20_SKY;1863 }1864 }1865 pmSource *mySrc = NULL;1866 psBool rc = false;1867 1868 pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST20_NUM_ROWS / 2),1869 (psF32) (TST20_NUM_COLS / 2),1870 200.0,1871 PM_PEAK_LONE);1872 1873 printf("Calling pmSourceLocalSky with valid data.\n");1874 tmpPeak->x = (psF32) (TST20_NUM_ROWS / 2);1875 tmpPeak->y = (psF32) (TST20_NUM_COLS / 2);1876 mySrc = pmSourceLocalSky(imgData,1877 tmpPeak,1878 PS_STAT_SAMPLE_MEAN,1879 (psF32) TST20_INNER_RADIUS,1880 (psF32) TST20_OUTER_RADIUS);1881 1882 if (mySrc == NULL) {1883 printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");1884 testStatus = false;1885 }1886 1887 mySrc->modelPSF = pmModelAlloc(PS_MODEL_GAUSS);1888 1889 1890 mySrc->modelPSF->params->data.F32[0] = 5.0;1891 mySrc->modelPSF->params->data.F32[1] = 70.0;1892 mySrc->modelPSF->params->data.F32[2] = (psF32) (TST20_NUM_ROWS / 2);1893 mySrc->modelPSF->params->data.F32[3] = (psF32) (TST20_NUM_COLS / 2);1894 mySrc->modelPSF->params->data.F32[4] = 1.0;1895 mySrc->modelPSF->params->data.F32[5] = 1.0;1896 mySrc->modelPSF->params->data.F32[6] = 2.0;1897 1898 printf("----------------------------------------------------------------------------------\n");1899 printf("Calling pmSourceFitModel with NULL psImage. Should generate error, return FALSE.\n");1900 rc = pmSourceFitModel(mySrc, NULL);1901 if (rc == true) {1902 printf("TEST ERROR: pmSourceFitModel() returned TRUE.\n");1903 testStatus = false;1904 }1905 1906 printf("----------------------------------------------------------------------------------\n");1907 printf("Calling pmSourceFitModel with NULL pmSource. Should generate error, return FALSE.\n");1908 rc = pmSourceFitModel(NULL, imgData);1909 if (rc == true) {1910 printf("TEST ERROR: pmSourceFitModel() returned TRUE.\n");1911 testStatus = false;1912 }1913 1914 printf("----------------------------------------------------------------------------------\n");1915 printf("Calling pmSourceFitModel with acceptable data.\n");1916 rc = pmSourceFitModel(mySrc, imgData);1917 printf("pmSourceFitModel returned %d\n", rc);1918 1919 // XXX: Memory leaks are not being tested1920 psVector *junk = psVectorAlloc(10, PS_TYPE_F32);1921 junk->data.F32[0] = 0.0;1922 1923 psFree(mySrc);1924 psFree(imgData);1925 return(testStatus);1926 }1927 1928 1929 977 // this code will 1930 978
Note:
See TracChangeset
for help on using the changeset viewer.
