Changeset 41892 for trunk/psModules
- Timestamp:
- Nov 4, 2021, 6:05:18 PM (5 years ago)
- Location:
- trunk/psModules
- Files:
-
- 24 edited
-
. (modified) (1 prop)
-
src/astrom/pmAstrometryDistortion.c (modified) (3 diffs)
-
src/astrom/pmAstrometryModel.c (modified) (9 diffs)
-
src/astrom/pmAstrometryObjects.c (modified) (7 diffs)
-
src/astrom/pmAstrometryObjects.h (modified) (1 diff)
-
src/astrom/pmAstrometryRegions.h (modified) (1 diff)
-
src/astrom/pmAstrometryUtils.c (modified) (5 diffs)
-
src/astrom/pmAstrometryUtils.h (modified) (1 diff)
-
src/astrom/pmAstrometryWCS.c (modified) (14 diffs)
-
src/camera/pmFPAConstruct.c (modified) (1 diff)
-
src/camera/pmFPAfile.c (modified) (2 diffs)
-
src/camera/pmFPAfile.h (modified) (1 diff)
-
src/camera/pmFPAfileFitsIO.c (modified) (1 diff)
-
src/camera/pmFPAfileIO.c (modified) (10 diffs)
-
src/camera/pmFPAfileIO.h (modified) (1 diff)
-
src/detrend/pmDetrendDB.c (modified) (1 diff)
-
src/detrend/pmDetrendDB.h (modified) (1 diff)
-
src/detrend/pmPattern.c (modified) (10 diffs)
-
src/detrend/pmPatternIO.c (modified) (2 diffs)
-
src/detrend/pmPatternIO.h (modified) (1 diff)
-
src/imcombine/pmStack.c (modified) (5 diffs)
-
src/imcombine/pmStack.h (modified) (1 diff)
-
src/objects/pmSourceIO_CMF.c.in (modified) (32 diffs)
-
src/objects/pmSourceIO_Ghosts.c (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules
-
trunk/psModules/src/astrom/pmAstrometryDistortion.c
r41810 r41892 29 29 #include "pmAstrometryRegions.h" 30 30 #include "pmAstrometryDistortion.h" 31 #include "pmAstrometryUtils.h" 31 32 #include "pmKapaPlots.h" 32 33 … … 183 184 PS_ASSERT_PTR_NON_NULL(fpa, false); 184 185 PS_ASSERT_ARRAY_NON_NULL(gradients, false); 186 187 int ExtraOrders = pmAstrometryGetExtraOrders(); 185 188 186 189 psPolynomial2D *localX = NULL; … … 340 343 psRegion *region = pmAstromFPAExtent (fpa); 341 344 342 // XXX psFree (fpa->fromTPA);343 // XXX psPlaneTransform *myPT = psPlaneTransformAlloc(fpa->toTPA->x->nX+4, fpa->toTPA->x->nY+4);344 // XXX fpa->fromTPA = psPlaneTransformInvert(myPT, fpa->toTPA, *region, 50);345 // XXX psFree (myPT);346 347 345 // as of r40806, psPlaneTransformInvert supplies the extra order (if non-linear) 348 346 psFree (fpa->fromTPA); 349 fpa->fromTPA = psPlaneTransformInvert(NULL, fpa->toTPA, *region, 100, 6);347 fpa->fromTPA = psPlaneTransformInvert(NULL, fpa->toTPA, *region, 50, ExtraOrders); 350 348 psFree (region); 351 349 -
trunk/psModules/src/astrom/pmAstrometryModel.c
r41810 r41892 461 461 bool status; 462 462 463 int ExtraOrders = pmAstrometryGetExtraOrders(); 464 463 465 // set FITS cursor 464 466 if (!psFitsMoveExtName (file->fits, "CHIPS")) { … … 498 500 int nY = psMetadataLookupS32(&status, row, "NYORDER"); REQUIRE (status, "missing NYORDER"); 499 501 if (chip->toFPA == NULL) { 500 chip->toFPA = psPlaneTransformAlloc(nX, nY); 502 chip->toFPA = psPlaneTransformAlloc(nX, nY, PS_POLYNOMIAL_ORD); // chip->fpa uses ordinary poly 501 503 } else { 502 504 REQUIRE (chip->toFPA->x->nX == nX, "mismatch in chip order"); … … 525 527 // as of r40806, psPlaneTransformInvert supplies the extra order (if non-linear) 526 528 psFree (chip->fromFPA); 527 chip->fromFPA = psPlaneTransformInvert(NULL, chip->toFPA, *region, 100, 6); 528 529 chip->fromFPA = psPlaneTransformInvert(NULL, chip->toFPA, *region, 50, ExtraOrders); 529 530 psFree (region); 530 531 } … … 539 540 540 541 bool status; 542 543 int ExtraOrders = pmAstrometryGetExtraOrders(); 541 544 542 545 if (!psFitsMoveExtName (file->fits, "FP")) { … … 565 568 if (file->fpa->toTPA == NULL) { 566 569 // allocate the new transformation 567 file->fpa->toTPA = psPlaneTransformAlloc(nX, nY );570 file->fpa->toTPA = psPlaneTransformAlloc(nX, nY, PS_POLYNOMIAL_ORD); // fpa->tpa uses ORD 568 571 } else { 569 572 REQUIRE (file->fpa->toTPA->x->nX == nX, "mismatch in chip order"); … … 585 588 psRegion *region = pmAstromFPAExtent (file->fpa); 586 589 587 // XXX psFree (file->fpa->fromTPA);588 // XXX psPlaneTransform *myPT = psPlaneTransformAlloc(file->fpa->toTPA->x->nX+4, file->fpa->toTPA->x->nY+4);589 // XXX file->fpa->fromTPA = psPlaneTransformInvert(myPT, file->fpa->toTPA, *region, 50);590 // XXX psFree (myPT);591 592 590 // as of r40806, psPlaneTransformInvert supplies the extra order (if non-linear) 593 591 psFree (file->fpa->fromTPA); 594 file->fpa->fromTPA = psPlaneTransformInvert(NULL, file->fpa->toTPA, *region, 100, 6);592 file->fpa->fromTPA = psPlaneTransformInvert(NULL, file->fpa->toTPA, *region, 50, ExtraOrders); 595 593 596 594 psFree (model); … … 689 687 bool status; 690 688 689 int ExtraOrders = pmAstrometryGetExtraOrders(); 690 691 691 // these externally supplied values are used to set the final transformation terms 692 692 double RA = psMetadataLookupF64 (&status, concepts, "FPA.RA"); REQUIRE (status, "missing FPA.RA"); … … 728 728 psLogMsg ("psModules.astrom", 4, "Position Angle: %f, Model Position Angle Zero Point: %f\n", POS, PosZero); 729 729 730 // psPlaneTransform *fromTPA = psPlaneTransformRotate (NULL, file->fpa->fromTPA, rotatorParity * (PosZero - POS));731 // psFree (file->fpa->fromTPA);732 // file->fpa->fromTPA = fromTPA;733 734 730 psPlaneTransform *toTPA = psPlaneTransformRotate (NULL, file->fpa->toTPA, rotatorParity * (POS - PosZero)); 735 731 psFree (file->fpa->toTPA); … … 739 735 psRegion *region = pmAstromFPAExtent (file->fpa); 740 736 741 // XXX psFree (file->fpa->fromTPA);742 // XXX psPlaneTransform *myPT = psPlaneTransformAlloc(file->fpa->toTPA->x->nX+4, file->fpa->toTPA->x->nY+4);743 // XXX file->fpa->fromTPA = psPlaneTransformInvert(myPT, file->fpa->toTPA, *region, 50);744 // XXX psFree (myPT);745 746 737 psFree (file->fpa->fromTPA); 747 file->fpa->fromTPA = psPlaneTransformInvert(NULL, file->fpa->toTPA, *region, 100, 10);738 file->fpa->fromTPA = psPlaneTransformInvert(NULL, file->fpa->toTPA, *region, 50, ExtraOrders); 748 739 749 740 psFree (region); -
trunk/psModules/src/astrom/pmAstrometryObjects.c
r41493 r41892 40 40 // XXX this is defined in pmPSFtry.h, which makes no sense 41 41 float psVectorSystematicError (psVector *residuals, psVector *errors, float clipFraction); 42 float pmAstrom2DSystematics (psVector *xPos, psVector *yPos, psVector *value); 42 43 43 44 #define PM_ASTROMETRYOBJECTS_DEBUG 1 … … 339 340 psVector *yResGood = psVectorAllocEmpty (match->n, PS_TYPE_F32); 340 341 342 // we measure the stdev of the median residual in NxN bins. 343 // use only valid (not NAN) measurements 344 psVector *xPosValid = psVectorAllocEmpty (match->n, PS_TYPE_F32); 345 psVector *yPosValid = psVectorAllocEmpty (match->n, PS_TYPE_F32); 346 psVector *xResValid = psVectorAllocEmpty (match->n, PS_TYPE_F32); 347 psVector *yResValid = psVectorAllocEmpty (match->n, PS_TYPE_F32); 348 341 349 for (int i = 0; i < match->n; i++) { 342 350 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue; … … 344 352 pmAstromObj *rawStar = raw->data[pair->raw]; 345 353 if (!isfinite(rawStar->dMag)) continue; 354 355 bool isValid = true; 356 isValid = isValid & isfinite (x->data.F32[i]); 357 isValid = isValid & isfinite (y->data.F32[i]); 358 isValid = isValid & isfinite (xRes->data.F32[i]); 359 isValid = isValid & isfinite (yRes->data.F32[i]); 360 if (isValid) { 361 psVectorAppend (xPosValid, x->data.F32[i]); 362 psVectorAppend (yPosValid, y->data.F32[i]); 363 psVectorAppend (xResValid, xRes->data.F32[i]); 364 psVectorAppend (yResValid, yRes->data.F32[i]); 365 } 366 367 // for the systematic error, use only high S/N stars 346 368 if (rawStar->dMag > 0.02) continue; 347 369 … … 369 391 results->dXsys = results->dYsys = NAN; 370 392 results->dXrange = results->dYrange = NAN; 393 results->dXstdev = results->dYstdev = NAN; 371 394 } else { 372 395 results->dXsys = psVectorSystematicError (xResGood, xErr, 0.05); … … 375 398 results->dXrange = pmAstromVectorRange (xResGood, 0.1, 0.9, results->xStats->clippedStdev); 376 399 results->dYrange = pmAstromVectorRange (yResGood, 0.1, 0.9, results->yStats->clippedStdev); 377 } 378 379 psTrace ("psModules.astrom", 3, "dXsys: %f, dXrange: %f\n", results->dXsys, results->dXrange); 380 psTrace ("psModules.astrom", 3, "dYsys: %f, dYrange: %f\n", results->dYsys, results->dYrange); 400 401 results->dXstdev = pmAstrom2DSystematics (xPosValid, yPosValid, xResValid); 402 results->dYstdev = pmAstrom2DSystematics (xPosValid, yPosValid, yResValid); 403 } 404 405 psTrace ("psModules.astrom", 3, "dXsys: %f, dXrange: %f, dXstdev: %f\n", results->dXsys, results->dXrange, results->dXstdev); 406 psTrace ("psModules.astrom", 3, "dYsys: %f, dYrange: %f, dYstdev: %f\n", results->dYsys, results->dYrange, results->dYstdev); 381 407 382 408 psFree (xErr); … … 386 412 psFree (xResGood); 387 413 psFree (yResGood); 414 psFree (xPosValid); 415 psFree (yPosValid); 416 psFree (xResValid); 417 psFree (yResValid); 388 418 389 419 psFree (x); … … 395 425 396 426 return (results); 427 } 428 429 # define VAL_COUNT 9.0 430 # define MIN_COUNT 5.0 431 432 float pmAstrom2DSystematics (psVector *xPos, psVector *yPos, psVector *value) { 433 434 // pre-filter the values to ensure no NANs, other invalid 435 if (xPos->n < VAL_COUNT*2*2) { 436 return NAN; 437 } 438 439 // generate a grid covering the full range of x,y and measure the median value in each 440 // grid cell. calculate the stdev of those median values. 441 442 // VAL_COUNT (9) is the (min) goal density, but a single cell may have only MIN_COUNT (7) 443 // we have N points. require a min of 9 pts per cell (configurable?). grid is square. 444 // Ncell*Ncell*9 = Npts, Ncell = MIN(sqrt(Npts/9), 5) 445 446 int Ncell = PS_MIN(sqrt((float)(xPos->n / VAL_COUNT)), 2); // have to at least have a 2x2 grid 447 448 // find the range of x,y values 449 float xMin = 1e9, xMax = -1e9, yMin = 1e9, yMax = 1e9; 450 for (int i = 0; i < xPos->n; i++) { 451 xMin = PS_MIN(xPos->data.F32[i],xMin); 452 xMax = PS_MAX(xPos->data.F32[i],xMax); 453 yMin = PS_MIN(yPos->data.F32[i],yMin); 454 yMax = PS_MAX(yPos->data.F32[i],yMax); 455 } 456 457 float xStep = Ncell / (xMax - xMin); 458 float yStep = Ncell / (yMax - yMin); 459 460 if (isnan(xStep)) { 461 return NAN; 462 } 463 if (isnan(yStep)) { 464 return NAN; 465 } 466 467 psArray *xBin = psArrayAlloc (Ncell); 468 for (int ix = 0; ix < Ncell; ix++) { 469 psArray *yBin = psArrayAlloc (Ncell); 470 xBin->data[ix] = yBin; 471 for (int iy = 0; iy < Ncell; iy++) { 472 yBin->data[iy] = psVectorAllocEmpty(128, PS_TYPE_F32); 473 } 474 } 475 476 // xValue = ix/xStep + xMin -> ix = (xValue - xMin) * xStep; 477 478 for (int i = 0; i < xPos->n; i++) { 479 int ix = PS_MIN(PS_MAX(0, (xPos->data.F32[i] - xMin) * xStep), Ncell - 1); 480 int iy = PS_MIN(PS_MAX(0, (yPos->data.F32[i] - yMin) * yStep), Ncell - 1); 481 482 psArray *yBin = xBin->data[ix]; 483 psVector *Bin = yBin->data[iy]; 484 485 psVectorAppend(Bin, value->data.F32[i]); 486 } 487 488 psVector *sample = psVectorAllocEmpty (Ncell*Ncell, PS_TYPE_F32); 489 psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN); 490 491 // calculate the median for each vector and save on a vector 492 for (int ix = 0; ix < Ncell; ix++) { 493 psArray *yBin = xBin->data[ix]; 494 for (int iy = 0; iy < Ncell; iy++) { 495 psVector *Bin = yBin->data[iy]; 496 if (Bin->n < MIN_COUNT) { continue; } 497 498 // psVectorStats resets stats so we can call this repeatedly 499 psVectorStats (stats, Bin, NULL, NULL, 0); 500 if (isfinite(stats->sampleMedian)) { 501 psVectorAppend (sample, stats->sampleMedian); 502 } 503 } 504 } 505 506 stats->options = PS_STAT_SAMPLE_STDEV; 507 psVectorStats (stats, sample, NULL, NULL, 0); 508 float result = stats->sampleStdev; 509 510 if (!isfinite(stats->sampleStdev)) { 511 fprintf (stderr, "*** bad solution ***\n"); 512 } 513 514 // NOTE: the elements of xBin are freed automatically, which extends down to the vectors 515 psFree (xBin); 516 psFree (stats); 517 psFree (sample); 518 519 return result; 397 520 } 398 521 -
trunk/psModules/src/astrom/pmAstrometryObjects.h
r39926 r41892 102 102 double dXrange; ///< 10% - 90% range X residuals (unmasked, high S/N) 103 103 double dYrange; ///< 10% - 90% range Y residuals (unmasked, high S/N) 104 double dXstdev; ///< stdev of median residual in NxN bins 105 double dYstdev; ///< stdev of median residual in NxN bins 104 106 } 105 107 pmAstromFitResults; -
trunk/psModules/src/astrom/pmAstrometryRegions.h
r12518 r41892 10 10 #ifndef PM_ASTROMETRY_REGIONS_H 11 11 #define PM_ASTROMETRY_REGIONS_H 12 13 // used by pmAstrometryDistortion.c, pmAstrometryWCS.c, pmAstrometryModel.c 14 // # define EXTRA_ORDERS 6 12 15 13 16 /// @addtogroup Astrometry -
trunk/psModules/src/astrom/pmAstrometryUtils.c
r35768 r41892 23 23 #include "pmAstrometryUtils.h" 24 24 25 static int transform_extra_orders = 3; 26 27 int pmAstrometryGetExtraOrders (void) { 28 return transform_extra_orders; 29 } 30 31 int pmAstrometrySetExtraOrders (int orders) { 32 transform_extra_orders = orders; 33 return transform_extra_orders; 34 } 35 25 36 // this is used by the test output block 26 37 static int Nout = 0; … … 120 131 121 132 // convert a transformation L(x,y) to L'(x-xo,y-yo) 133 // is this used for an upward (e.g., chip->fpa) or a downward (fpa->chip) transform? 122 134 psPlaneTransform *psPlaneTransformSetCenter (psPlaneTransform *output, psPlaneTransform *input, double Xo, double Yo) 123 135 { 124 136 125 // validate fit order 137 // validate fit type: 138 // polynomial in input transforms must match type -- and for now be ORD 139 psAssert (input->x->type == PS_POLYNOMIAL_ORD, "fix for CHEB"); 140 psAssert (input->y->type == PS_POLYNOMIAL_ORD, "fix for CHEB"); 126 141 127 142 if (output == NULL) { 128 output = psPlaneTransformAlloc(input->x->nX, input->x->nY );143 output = psPlaneTransformAlloc(input->x->nX, input->x->nY, PS_POLYNOMIAL_ORD); 129 144 } 130 145 … … 169 184 170 185 // rotate a transformation L(x,y) by theta 171 psPlaneTransform *psPlaneTransformRotate (psPlaneTransform *output, psPlaneTransform *input, double theta)186 psPlaneTransform *psPlaneTransformRotate (psPlaneTransform *output, psPlaneTransform *input, double theta) 172 187 { 173 188 /* given the polynomial transformations: … … 181 196 182 197 if (output == NULL) { 183 output = psPlaneTransformAlloc(input->x->nX, input->x->nY); 198 // generate a new transform using the same order and type as the input 199 output = psPlaneTransformAlloc(input->x->nX, input->x->nY, input->x->type); 184 200 } 185 201 … … 216 232 217 233 // all coeffs and masks initially set to 0 218 transform = psPlaneTransformAlloc (order, order );234 transform = psPlaneTransformAlloc (order, order, PS_POLYNOMIAL_ORD); 219 235 220 236 for (int i = 0; i <= order; i++) { -
trunk/psModules/src/astrom/pmAstrometryUtils.h
r15884 r41892 25 25 bool psPlaneDistortIsDiagonal (psPlaneDistort *distort); 26 26 27 int pmAstrometryGetExtraOrders (void); 28 int pmAstrometrySetExtraOrders (int orders); 29 27 30 /// @} 28 31 #endif -
trunk/psModules/src/astrom/pmAstrometryWCS.c
r41810 r41892 501 501 psPlaneTransform *toFPA; 502 502 503 int ExtraOrders = pmAstrometryGetExtraOrders(); 504 503 505 // create transformation with 0,0 reference pixel and units of degrees/pixel 504 506 toFPA = psPlaneTransformSetCenter (NULL, wcs->trans, -wcs->crpix1, -wcs->crpix2); … … 552 554 // apply the exiting fromTPA transformation to make the new toFPA consistent with the toTPA layter 553 555 // XXX this only works if toTPA is at most a linear transformation 554 psPlaneTransform *toFPAnew = psPlaneTransformAlloc(toFPA->x->nX, toFPA->x->nY );556 psPlaneTransform *toFPAnew = psPlaneTransformAlloc(toFPA->x->nX, toFPA->x->nY, PS_POLYNOMIAL_ORD); 555 557 for (int i = 0; i <= toFPA->x->nX; i++) { 556 558 for (int j = 0; j <= toFPA->x->nY; j++) { … … 608 610 // as of r40806, psPlaneTransformInvert supplies the extra order (if non-linear) 609 611 psFree (chip->fromFPA); 610 chip->fromFPA = psPlaneTransformInvert(NULL, chip->toFPA, *region, 100, 6);612 chip->fromFPA = psPlaneTransformInvert(NULL, chip->toFPA, *region, 50, ExtraOrders); 611 613 psFree (region); 612 614 … … 648 650 */ 649 651 652 int ExtraOrders = pmAstrometryGetExtraOrders(); 653 650 654 psFree (chip->toFPA); 651 655 if ((fabs(wcs->crpix1) > 0.01) || (fabs(wcs->crpix2) > 0.01)) { 652 656 chip->toFPA = psPlaneTransformSetCenter (NULL, wcs->trans, -wcs->crpix1, -wcs->crpix2); 653 657 } else { 654 chip->toFPA = psPlaneTransformAlloc(wcs->trans->x->nX, wcs->trans->x->nY );658 chip->toFPA = psPlaneTransformAlloc(wcs->trans->x->nX, wcs->trans->x->nY, PS_POLYNOMIAL_ORD); 655 659 656 660 // copy the toFPA x,y, transformations to the wcs version … … 668 672 // as of r40806, psPlaneTransformInvert supplies the extra order (if non-linear) 669 673 psFree (chip->fromFPA); 670 chip->fromFPA = psPlaneTransformInvert(NULL, chip->toFPA, *region, 100, 6);674 chip->fromFPA = psPlaneTransformInvert(NULL, chip->toFPA, *region, 50, ExtraOrders); 671 675 psFree (region); 672 676 … … 700 704 // the region defines the FPA pixels covered by the tranformation 701 705 psFree (fpa->fromTPA); 702 int additional_orders = 4; // This is the number of orders that should be added.706 int additional_orders = pmAstrometryGetExtraOrders(); // This is the number of orders that should be added. 703 707 bool status = false; 704 708 int config_additional_orders = psMetadataLookupS32(&status,fpa->analysis, "ADDITIONAL_WCS_ORDERS"); … … 706 710 additional_orders = config_additional_orders; 707 711 } 708 fpa->fromTPA = psPlaneTransformInvert(NULL, fpa->toTPA, region, 100, additional_orders);712 fpa->fromTPA = psPlaneTransformInvert(NULL, fpa->toTPA, region, 50, additional_orders); 709 713 return true; 710 714 } … … 739 743 // XXX require fpa->toTPA->nX == 1 740 744 741 psPlaneTransform *toTPA = psPlaneTransformAlloc(chip->toFPA->x->nX, chip->toFPA->x->nY );745 psPlaneTransform *toTPA = psPlaneTransformAlloc(chip->toFPA->x->nX, chip->toFPA->x->nY, PS_POLYNOMIAL_ORD); 742 746 743 747 for (int i = 0; i <= toTPA->x->nX; i++) { … … 958 962 } 959 963 960 psPlaneTransform *newTrans = psPlaneTransformAlloc(1, 1 );964 psPlaneTransform *newTrans = psPlaneTransformAlloc(1, 1, PS_POLYNOMIAL_ORD); 961 965 962 966 if (!psPlaneTransformFit(newTrans, src, dst, 0, 0)) { … … 997 1001 PS_ASSERT_PTR_NON_NULL(inChip, NULL); 998 1002 1003 int ExtraOrders = pmAstrometryGetExtraOrders(); 1004 999 1005 if (outFPA == NULL) { 1000 1006 outFPA = inFPA; … … 1032 1038 1033 1039 // NOTE: the extraOrders value (4) should be ignored since outToFPA is specified to be linear 1034 psPlaneTransform *outFromFPA = psPlaneTransformInvert(NULL, outToFPA, *outputBounds, 100, 6);1040 psPlaneTransform *outFromFPA = psPlaneTransformInvert(NULL, outToFPA, *outputBounds, 50, ExtraOrders); 1035 1041 if (!outFromFPA) { 1036 1042 psFree(outToFPA); … … 1116 1122 } 1117 1123 1118 psPlaneTransform *newToFPA = psPlaneTransformAlloc(1, 1 );1124 psPlaneTransform *newToFPA = psPlaneTransformAlloc(1, 1, PS_POLYNOMIAL_ORD); 1119 1125 newToFPA->x->coeffMask[1][1] = 1; 1120 1126 newToFPA->y->coeffMask[1][1] = 1; … … 1148 1154 psFree(dst); 1149 1155 1150 // this is a linear transformation 1156 // this is a linear transformation, no extra orders are needed 1151 1157 psPlaneTransform *newFromFPA = psPlaneTransformInvert(NULL, newToFPA, *bounds, 1, 0); 1152 1158 if (!newFromFPA) { … … 1187 1193 psMemSetDeallocator(wcs, (psFreeFunc) pmAstromWCSFree); 1188 1194 1189 wcs->trans = psPlaneTransformAlloc (nXorder, nYorder); 1195 // note: WCS transforms are always defined as chip to sky 1196 wcs->trans = psPlaneTransformAlloc (nXorder, nYorder, PS_POLYNOMIAL_ORD); 1190 1197 wcs->toSky = NULL; 1191 1198 wcs->wcsCDkeys = 0; -
trunk/psModules/src/camera/pmFPAConstruct.c
r35561 r41892 853 853 } else { 854 854 const char *content = getContent(fileInfo, phdu->header, contents); // The chip type 855 if (!content) { 856 psError(PS_ERR_UNKNOWN, false, "Unable to find CONTENT entry in header"); 857 return false; 858 } 855 859 856 860 int chipNum = -1; // Chip number -
trunk/psModules/src/camera/pmFPAfile.c
r41535 r41892 551 551 if (!strcasecmp(type, "KH.CORRECT")) { 552 552 return PM_FPA_FILE_KH_CORRECT; 553 } 554 if (!strcasecmp(type, "PATTERN.ROW.AMP")) { 555 return PM_FPA_FILE_PATTERN_ROW_AMP; 553 556 } 554 557 if (!strcasecmp(type, "SUBKERNEL")) { … … 606 609 case PM_FPA_FILE_KH_CORRECT: 607 610 return ("KH.CORRECT"); 611 case PM_FPA_FILE_PATTERN_ROW_AMP: 612 return ("PATTERN.ROW.AMP"); 608 613 case PM_FPA_FILE_SUBKERNEL: 609 614 return ("SUBKERNEL"); -
trunk/psModules/src/camera/pmFPAfile.h
r36834 r41892 52 52 PM_FPA_FILE_SRCTEXT, 53 53 PM_FPA_FILE_PATTERN, 54 PM_FPA_FILE_PATTERN_ROW_AMP, 54 55 PM_FPA_FILE_LINEARITY, 55 56 PM_FPA_FILE_EXPNUM, -
trunk/psModules/src/camera/pmFPAfileFitsIO.c
r36834 r41892 152 152 case PM_FPA_FILE_ASTROM_REFSTARS: 153 153 case PM_FPA_FILE_KH_CORRECT: 154 case PM_FPA_FILE_PATTERN_ROW_AMP: 154 155 { 155 156 pmHDU *hdu = pmFPAviewThisHDU(view, fpa); -
trunk/psModules/src/camera/pmFPAfileIO.c
r41535 r41892 145 145 } 146 146 147 // list all defined pmFPAfiles 148 bool pmFPAfileIOList (pmConfig *config) 149 { 150 PS_ASSERT_PTR_NON_NULL(config, false); 151 PS_ASSERT_PTR_NON_NULL(config->files, false); 152 153 psMetadata *files = config->files; 154 155 // attempt to perform all create, read, write, close operations 156 psMetadataItem *item = NULL; 157 psMetadataIterator *iter = psMetadataIteratorAlloc (files, PS_LIST_HEAD, NULL); 158 while ((item = psMetadataGetAndIncrement (iter)) != NULL) { 159 pmFPAfile *file = item->data.V; 160 161 fprintf (stderr, "%s : %d %d %d : %d %d %d %d\n", file->name, file->type, file->mode, file->state, 162 file->fileLevel, file->dataLevel, file->freeLevel, file->mosaicLevel); 163 } 164 psFree (iter); 165 return true; 166 } 167 147 168 // read the file, if necessary and possible 148 169 bool pmFPAfileRead(pmFPAfile *file, const pmFPAview *view, pmConfig *config) … … 231 252 case PM_FPA_FILE_PATTERN: 232 253 status = pmPatternRead(view, file, config); 254 break; 255 case PM_FPA_FILE_PATTERN_ROW_AMP: 256 status = pmPatternRowAmpRead(view, file, config); 233 257 break; 234 258 case PM_FPA_FILE_SX: … … 342 366 case PM_FPA_FILE_ASTROM_REFSTARS: 343 367 case PM_FPA_FILE_KH_CORRECT: 368 case PM_FPA_FILE_PATTERN_ROW_AMP: 344 369 case PM_FPA_FILE_JPEG: 345 370 case PM_FPA_FILE_KAPA: … … 359 384 360 385 if (file->state & PM_FPA_STATE_INACTIVE) { 361 psTrace("psModules.camera", 6, "skip write for %s, file sis inactive", file->name);386 psTrace("psModules.camera", 6, "skip write for %s, file is inactive", file->name); 362 387 return true; 363 388 } … … 430 455 return true; 431 456 } 457 if (file->type == PM_FPA_FILE_PATTERN_ROW_AMP) { 458 psTrace("psModules.camera", 6, "skip write for %s, no write function defined", file->name); 459 return true; 460 } 432 461 433 462 // open the file if not yet opened … … 526 555 case PM_FPA_FILE_KH_CORRECT: 527 556 psError(PS_ERR_IO, true, "cannot write type KH.CORRECT (%s)", file->name); 557 break; 558 559 case PM_FPA_FILE_PATTERN_ROW_AMP: 560 psError(PS_ERR_IO, true, "cannot write type PATTERN.ROW.AMP (%s)", file->name); 528 561 break; 529 562 … … 603 636 case PM_FPA_FILE_ASTROM_REFSTARS: 604 637 case PM_FPA_FILE_KH_CORRECT: 638 case PM_FPA_FILE_PATTERN_ROW_AMP: 605 639 case PM_FPA_FILE_LINEARITY: 606 640 case PM_FPA_FILE_EXPNUM: … … 681 715 case PM_FPA_FILE_ASTROM_REFSTARS: 682 716 case PM_FPA_FILE_KH_CORRECT: 717 case PM_FPA_FILE_PATTERN_ROW_AMP: 683 718 case PM_FPA_FILE_EXPNUM: 684 719 psTrace ("psModules.camera", 6, "NOT freeing %s (%s) : save for further analysis\n", file->filename, file->name); … … 844 879 case PM_FPA_FILE_ASTROM_REFSTARS: 845 880 case PM_FPA_FILE_KH_CORRECT: 881 case PM_FPA_FILE_PATTERN_ROW_AMP: 846 882 case PM_FPA_FILE_LINEARITY: 847 883 case PM_FPA_FILE_EXPNUM: … … 1048 1084 case PM_FPA_FILE_ASTROM_MODEL: 1049 1085 case PM_FPA_FILE_KH_CORRECT: 1086 case PM_FPA_FILE_PATTERN_ROW_AMP: 1050 1087 case PM_FPA_FILE_SX: 1051 1088 case PM_FPA_FILE_RAW: -
trunk/psModules/src/camera/pmFPAfileIO.h
r23576 r41892 55 55 bool pmFPAfileReadPHU (pmFPAfile *file, const pmFPAview *view, pmConfig *config); 56 56 57 bool pmFPAfileIOList (pmConfig *config); 58 57 59 /// @} 58 60 # endif -
trunk/psModules/src/detrend/pmDetrendDB.c
r38038 r41892 112 112 DETREND_STRING_CASE(AUXMASK); 113 113 DETREND_STRING_CASE(KH_CORRECT); 114 DETREND_STRING_CASE(PATTERN_ROW_AMP); 114 115 default: 115 116 return NULL; -
trunk/psModules/src/detrend/pmDetrendDB.h
r36834 r41892 41 41 PM_DETREND_TYPE_AUXMASK, 42 42 PM_DETREND_TYPE_KH_CORRECT, 43 PM_DETREND_TYPE_PATTERN_ROW_AMP, 43 44 } pmDetrendType; 44 45 -
trunk/psModules/src/detrend/pmPattern.c
r41743 r41892 9 9 #define PATTERN_ROW_BKG_FIX 1 10 10 11 /* some in-line notes: 12 13 patternMaskRow sets the data value to NAN, inconsistent with new plan 14 15 here is the outline of pmPatternRow 16 17 * at this point, we have already done overscan subtraction, right? 18 19 * measure stats on the full cell (MEDIAN, STDEV) 20 ** subsample? 21 ** if it fails, it masks the entire cell and set the value to NAN 22 23 * calculate an upper and lower threshold (median +/- T * sigma) 24 * define a normalized x-coordinate ('index') : 25 ** see note below on chebys 26 27 * each row is treated independently 28 * pixels are masked for the fit if they are out-of-range 29 or if they are already masked 30 31 ** note that the clipping threshold will be larger if there 32 are pixels which have astronomical structures 33 34 a possible better option would be to set the threshold based on the median 35 and a sigma calculated from Poisson stats (do we know the gain?) 36 37 ** fit is allowed to proceed if even N+1 pixels exist, which is clearly too low 38 39 ** Remaining pixels are fitted with clip-fit 40 41 ** solution is subtracted from the data 42 (this is implemented with psPolynomial1DEvalVector) 43 perhaps faster if we fixed the order to 2 and hardwired the result 44 45 * after each row is fitted, the intercept (A value) is fitted 46 as a function of the y-coordinate and the result is subtracted 47 48 * the slope value is also fitted as a function of the column 49 and added back in -- I'm not sure I understand this step. 50 51 ***************** 52 53 ** what we calculate are related to chebychevs (domain is -1 : +1) 54 *** T0(x) = 1 55 *** T1(x) = x 56 *** T2(x) = 2x^2 - 1 57 58 *** we calculate y = A + Bx + Cx^2 59 60 a_0 + a_1 x + a_2 (2x^2 - 1) = A + B + Cx^2 61 62 a_1 = B 63 a_0 - a_2 = A 64 2 a_2 = C 65 66 a_0 = A + C/2 67 a_1 = B 68 a_2 = C/2 69 70 ***************** 71 72 I have 3 goals in re-working the code: 73 74 1) improve overall speed 75 2) improve reliability of the fit 76 3) skip fit if we can 77 78 Let's assume the signal in the cell is light + bias drift 79 80 The bias drift has an amplitude of ~5 - 10 DN 81 82 That makes a detectable source with ~N * a few counts (multiple pixels in a row) 83 84 So, the effective flux is ~10 * 5 = 50 DN 85 for which sky level is this value - 3 sigma? 86 87 50 / sqrt(sky sigma^2 * effective area) 88 89 area ~ 5pixels, sky sigma^2 = sky 90 91 10 * Npix / sqrt(sky * Npix) = 3 92 93 Npix = sky * (S/N)^2 / (peak^2) 94 95 sky = Npix * peak^2 / SN^2 96 97 if (sky < Npix * peak^2 / SN^2), we should skip: 98 99 Npix ~ 5 100 peak ~ 10 101 SN ~ 3 (or even less) 102 103 sky < 5 * 100 / 9 = 55 or so 104 105 106 To address these in order: 107 108 1) speed: 109 * the analysis threaded is not threaded: thread across cells 110 111 2) 112 113 */ 11 114 12 115 // Mask a row as bad … … 33 136 } 34 137 138 // Comparison and swap functions for sorting values directly 139 #define SORT_COMPARE(A,B) (sampleArray[A] < sampleArray[B]) 140 #define SORT_SWAP(TYPE,A,B) { \ 141 if (A != B) { \ 142 TYPE temp = sampleArray[A]; \ 143 sampleArray[A] = sampleArray[B]; \ 144 sampleArray[B] = temp; \ 145 } \ 146 } 147 35 148 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 36 149 // Measurement and application 37 150 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 38 151 152 bool pmPatternRowUnbinned(pmReadout *ro, int order, int iter, float rej, float thresh, 153 psStatsOptions clipMean, psStatsOptions clipStdev, 154 psImageMaskType maskVal, psImageMaskType maskBad); 155 156 157 bool pmPatternRowBinned(pmReadout *ro, int order, int iter, float rej, float thresh, 158 psStatsOptions clipMean, psStatsOptions clipStdev, 159 psImageMaskType maskVal, psImageMaskType maskBad); 160 161 162 // XXX allow user choice of binned vs unbinned analysis? 39 163 bool pmPatternRow(pmReadout *ro, int order, int iter, float rej, float thresh, 164 psStatsOptions clipMean, psStatsOptions clipStdev, 165 psImageMaskType maskVal, psImageMaskType maskBad) { 166 167 bool status = false; 168 if (true) { 169 status = pmPatternRowBinned(ro, order, iter, rej, thresh, clipMean, clipStdev, maskVal, maskBad); 170 } else { 171 status = pmPatternRowUnbinned(ro, order, iter, rej, thresh, clipMean, clipStdev, maskVal, maskBad); 172 } 173 return status; 174 } 175 176 // USE_BACKGROUND_STDEV: if TRUE, the analysis will use the measured robust stdev to clip the out-of-range pixles 177 // if FALSE, the stdev will be estimated based on the Poisson statistics of the median (sky level). 178 # define USE_BACKGROUND_STDEV 0 179 180 bool pmPatternRowUnbinned(pmReadout *ro, int order, int iter, float rej, float thresh, 40 181 psStatsOptions clipMean, psStatsOptions clipStdev, 41 182 psImageMaskType maskVal, psImageMaskType maskBad) … … 48 189 PS_ASSERT_FLOAT_LARGER_THAN(thresh, 0.0, false); 49 190 191 bool mdok; // Status of MD lookup 192 193 pmCell *cell = ro->parent; 194 pmChip *chip = cell->parent; 195 const char *chipName = psMetadataLookupStr(&mdok, chip->concepts, "CHIP.NAME"); // Name of chip 196 const char *cellName = psMetadataLookupStr(&mdok, cell->concepts, "CELL.NAME"); // Name of cell 197 50 198 psImage *image = ro->image; // Image to correct 51 199 psImage *mask = ro->mask; // Mask for image … … 55 203 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 56 204 if (!psImageBackground(stats, NULL, ro->image, ro->mask, maskVal, rng)) { 57 psWarning("Unable to calculate statistics on readout; masking entire readout.");205 psWarning("Unable to calculate statistics on readout; skipping pattern correction for %s, %s.", chipName, cellName); 58 206 psErrorClear(); 59 207 psFree(stats); 60 208 psFree(rng); 61 psImageInit(image, NAN);62 if (mask) {63 psBinaryOp(mask, mask, "|", psScalarAlloc(maskBad, PS_TYPE_IMAGE_MASK));64 }65 if (ro->variance) {66 psImageInit(image, NAN);67 }68 209 return true; 69 210 } 211 212 # if (USE_BACKGROUND_STDEV) 70 213 float lower = stats->robustMedian - thresh * stats->robustStdev; // Lower bound for data 71 214 float upper = stats->robustMedian + thresh * stats->robustStdev; // Upper bound for data 72 215 float background = stats->robustMedian; 216 # else 217 // the signal we are looking for is a small variation on top of the background. if 218 // the background is uniform with only read noise + sky noise, then the pixel-to-pixel 219 // stdev should only be due to known noise sources and predictable. If the 220 // pixel-to-pixel variations are from other features, then those variations will 221 // probably dominate the row-by-row bias variations. 222 223 // instead of using the image pixel statistics to measure the stdev, lets assume only 224 // dark noise plus poisson sky noise. we are not carrying in the read noise, but it is 225 // fairly modest for GPC1 (~10 DN) 226 227 // if we assume a gain of 1 and the read noise of 10 DN, then a sky of 200 would have 228 // a noise of N = sqrt (1 * 200 + 10^2) = sqrt (300) ~ 17 229 230 // if the gain were as much as 2, then the noise in DN would be N = sqrt(2 * (200 + 100)) / 2 = sqrt(300) / sqrt(2) 231 // so smaller by a factor of 1.4 than what we predict, which is not very large 232 233 // find the nominal signal amplitude (check the ghost and/or crosstalk recipe file) 234 float nominalAmplitude = psMetadataLookupF32 (&mdok, cell->analysis, "PTN.ROW.AMP"); 235 if (!mdok) nominalAmplitude = 20; // XXX EAM : somewhat arbitrary number 236 // If we cannot determine the nominal amplitude, we fall-back on the worst case 237 238 // XXX retrieve noise and gain from 'concepts' if possible 239 # define READNOISE 10 /* arbitrary number */ 240 float sigma = sqrt(stats->robustMedian + PS_SQR(READNOISE)); 241 float delta = PS_MIN (thresh * sigma, 2*nominalAmplitude); 242 float lower = stats->robustMedian - delta; // Lower bound for data 243 float upper = stats->robustMedian + delta; // Upper bound for data 244 float background = stats->robustMedian; 245 246 // if the noise from the background is too large 247 float significance = nominalAmplitude / sigma; 248 249 // XXX EAM : arbitrary number 250 if (isfinite(nominalAmplitude) && (significance < 1.0/6.0)) { 251 psLogMsg("ppImage", PS_LOG_INFO, "Skipping row pattern correction for %s, %s, stats: %f - %f - %f : %f %f %f\n", chipName, cellName, lower, background, upper, sigma, nominalAmplitude, significance); 252 return true; 253 } 254 fprintf (stderr, "correcting pattern row background %s: %f - %f - %f : %f %f %f\n", cellName, lower, background, upper, sigma, nominalAmplitude, significance); 255 psLogMsg("ppImage", PS_LOG_INFO, "Performing row pattern correction for %s, %s, stats: %f - %f - %f : %f %f %f\n", chipName, cellName, lower, background, upper, sigma, nominalAmplitude, significance); 256 # endif 257 73 258 psFree(stats); 74 259 psFree(rng); … … 109 294 psVectorInit(yaxisMask, 0); 110 295 #endif 296 297 // we really need more than order + 1 points (= 4). 298 // this should be tunable, but let's try 5 - 10% 299 int validNmin = numCols * 0.1; 300 111 301 for (int y = 0; y < numRows; y++) { 112 302 psVectorInit(clipMask, 0); 113 303 data = psImageRow(data, image, y); 114 304 int num = 0; // Number of good pixels 305 306 // if the unmasked pixels only span a small range in x then we cannot fit the 307 // 2nd order polynomial variations very well. Require a minimum fractional range 308 float validXmin = +1; 309 float validXmax = -1; 310 311 // XXX can we do just as well fitting 1/3 of the pixels? (NOT REALLY) 312 // (x % 3) || 115 313 for (int x = 0; x < numCols; x++) { 116 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) ||117 data->data.F32[x] < lower || data->data.F32[x] > upper) {118 clipMask->data.PS_TYPE_VECTOR_MASK_DATA[x] = 0xFF;314 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) || 315 data->data.F32[x] < lower || data->data.F32[x] > upper) { 316 clipMask->data.PS_TYPE_VECTOR_MASK_DATA[x] = 0xFF; 119 317 } else { 120 318 clipMask->data.PS_TYPE_VECTOR_MASK_DATA[x] = 0; 121 319 num++; 320 validXmin = PS_MIN(indices->data.F32[x], validXmin); 321 validXmax = PS_MAX(indices->data.F32[x], validXmax); 122 322 } 123 323 } 124 if (num < order + 1) { 324 325 // XXX how much time is spent in the fitting 326 if (num < validNmin) { 125 327 // Not enough points to fit 126 328 patternMaskRow(ro, y, maskBad); … … 131 333 continue; 132 334 } 335 // XXX does this need to be a clipped fit if we are clipping based on the median poisson noise? 133 336 if (!psVectorClipFitPolynomial1D(poly, clip, clipMask, 0xFF, data, NULL, indices)) { 134 337 psWarning("Unable to fit polynomial to row %d", y); … … 215 418 for (int x = 0; x < numCols; x++) { 216 419 image->data.F32[y][x] += solution->data.F32[y]; 217 psTrace("pattern",5,"B: %d %d %g\n",x,y,solution->data.F32[ x]);420 psTrace("pattern",5,"B: %d %d %g\n",x,y,solution->data.F32[y]); 218 421 } 219 422 corr->data.F64[y][0] -= solution->data.F32[y]; … … 241 444 for (int x = 0; x < numCols; x++) { 242 445 image->data.F32[y][x] += solution->data.F32[y] * indices->data.F32[x]; 243 psTrace("pattern",5,"C: %d %d %g %g\n",x,y,solution->data.F32[x],indices->data.F32[x]); 446 // XXX EAM : this was [x] which is wrong 447 psTrace("pattern",5,"C: %d %d %g %g\n",x,y,solution->data.F32[y],indices->data.F32[x]); 244 448 } 245 449 corr->data.F64[y][1] -= solution->data.F32[y] ; … … 262 466 263 467 psFree(indices); 468 psFree(clip); 469 psFree(clipMask); 470 psFree(poly); 471 psFree(data); 472 473 return true; 474 } 475 476 # define NPIX 15 477 478 // bin by NPIX in the x-direction to reduce the number of calculations needed to measure 479 // the pattern 480 bool pmPatternRowBinned(pmReadout *ro, int order, int iter, float rej, float thresh, 481 psStatsOptions clipMean, psStatsOptions clipStdev, 482 psImageMaskType maskVal, psImageMaskType maskBad) 483 { 484 PM_ASSERT_READOUT_NON_NULL(ro, false); 485 PM_ASSERT_READOUT_IMAGE(ro, false); 486 PS_ASSERT_INT_NONNEGATIVE(order, false); 487 PS_ASSERT_INT_NONNEGATIVE(iter, false); 488 PS_ASSERT_FLOAT_LARGER_THAN(rej, 0.0, false); 489 PS_ASSERT_FLOAT_LARGER_THAN(thresh, 0.0, false); 490 491 bool mdok; // Status of MD lookup 492 493 pmCell *cell = ro->parent; 494 pmChip *chip = cell->parent; 495 const char *chipName = psMetadataLookupStr(&mdok, chip->concepts, "CHIP.NAME"); // Name of chip 496 const char *cellName = psMetadataLookupStr(&mdok, cell->concepts, "CELL.NAME"); // Name of cell 497 498 psImage *image = ro->image; // Image to correct 499 psImage *mask = ro->mask; // Mask for image 500 int numCols = image->numCols, numRows = image->numRows; // Size of image 501 502 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 503 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 504 if (!psImageBackground(stats, NULL, ro->image, ro->mask, maskVal, rng)) { 505 psWarning("Unable to calculate statistics on readout; skipping pattern correction for %s, %s.", chipName, cellName); 506 psErrorClear(); 507 psFree(stats); 508 psFree(rng); 509 510 // EAM 20211011 : we used to mask cells which fail the above, but this seems excessive 511 // psImageInit(image, NAN); 512 // if (mask) { 513 // psBinaryOp(mask, mask, "|", psScalarAlloc(maskBad, PS_TYPE_IMAGE_MASK)); 514 // } 515 // if (ro->variance) { 516 // psImageInit(image, NAN); 517 // } 518 return true; 519 } 520 521 // if USE_BACKGROUND_STDEV is TRUE, the observed standard deviation is used to set the 522 // thresholds. this is going to be an overestimate if there is any structure in the 523 // image. If FALSE, the thresholds are set based on poisson stats for the background 524 // level. We assume the gain is 1, so this is an overestimate if the gain is > 1 525 526 # if (USE_BACKGROUND_STDEV) 527 float lower = stats->robustMedian - thresh * stats->robustStdev; // Lower bound for data 528 float upper = stats->robustMedian + thresh * stats->robustStdev; // Upper bound for data 529 float background = stats->robustMedian; 530 # else 531 // the signal we are looking for is a small variation on top of the background. if 532 // the background is uniform with only read noise + sky noise, then the pixel-to-pixel 533 // stdev should only be due to known noise sources and predictable. If the 534 // pixel-to-pixel variations are from other features, then those variations will 535 // probably dominate the row-by-row bias variations. 536 537 // instead of using the image pixel statistics to measure the stdev, lets assume only 538 // dark noise plus poisson sky noise. we are not carrying in the read noise, but it is 539 // fairly modest for GPC1 (~10 DN) 540 541 // if we assume a gain of 1 and the read noise of 10 DN, then a sky of 200 would have 542 // a noise of N = sqrt (1 * 200 + 10^2) = sqrt (300) ~ 17 543 544 // if the gain were as much as 2, then the noise in DN would be N = sqrt(2 * (200 + 100)) / 2 = sqrt(300) / sqrt(2) 545 // so smaller by a factor of 1.4 than what we predict, which is not very large 546 547 // find the nominal signal amplitude (check the ghost and/or crosstalk recipe file) 548 float nominalAmplitude = psMetadataLookupF32 (&mdok, cell->analysis, "PTN.ROW.AMP"); 549 if (!mdok) nominalAmplitude = 20; // XXX EAM : somewhat arbitrary number 550 if (!isfinite(nominalAmplitude)) nominalAmplitude = 20; // XXX EAM : somewhat arbitrary number 551 // If we cannot determine the nominal amplitude, we fall-back on the worst case 552 553 // retrieve noise and gain from 'concepts' if possible 554 # define READNOISE 10 /* arbitrary number */ 555 float sigma = sqrt(stats->robustMedian + PS_SQR(READNOISE)); 556 float delta = PS_MIN (thresh * sigma, 5*nominalAmplitude); 557 float lower = stats->robustMedian - delta; // Lower bound for data 558 float upper = stats->robustMedian + delta; // Upper bound for data 559 float background = stats->robustMedian; 560 561 // if the noise from the background is too large 562 float significance = nominalAmplitude / sigma; 563 564 // XXX EAM : arbitrary number 565 if (isfinite(nominalAmplitude) && (significance < 1.0/6.0)) { 566 psLogMsg("ppImage", PS_LOG_INFO, "Skipping row pattern correction for %s, %s, stats: %f - %f - %f : %f %f %f\n", chipName, cellName, lower, background, upper, sigma, nominalAmplitude, significance); 567 psFree(stats); 568 psFree(rng); 569 return true; 570 } 571 psLogMsg("ppImage", PS_LOG_INFO, "Performing row pattern correction for %s, %s, stats: %f - %f - %f : %f %f %f\n", chipName, cellName, lower, background, upper, sigma, nominalAmplitude, significance); 572 # endif 573 574 psFree(stats); 575 psFree(rng); 576 577 // the vector 'indices' maps the x-coordinate to a range [-1:1]. the element number (i) of indices 578 // related to the x-coordinate (column number) by x = (i + 0.5) * NPIX 579 580 int nSamples = numCols / NPIX; 581 582 psVector *indices = psVectorAlloc(numCols, PS_TYPE_F32); // Indices for fit solutions 583 psVector *xFit = psVectorAlloc(nSamples, PS_TYPE_F32); // x-coordinate for fitting 584 psVector *yFit = psVectorAlloc(nSamples, PS_TYPE_F32); // flux values for fitting 585 586 // xFit elements run from 0 - nSamples, element 'sample' corresponds to the middle of the bin sample*NPIX + 0.5*NPIX 587 588 float norm = 2.0 / (float)numCols; // Normalisation for indices 589 for (int sample = 0; sample < nSamples; sample ++) { 590 int x = (sample + 0.5)*NPIX; 591 xFit->data.F32[sample] = x * norm - 1.0; 592 } 593 for (int x = 0; x < numCols; x ++) { 594 indices->data.F32[x] = x * norm - 1.0; 595 } 596 597 psStats *clip = psStatsAlloc(clipMean | clipStdev); // Clipping statistics 598 clip->clipIter = iter; 599 clip->clipSigma = rej; 600 psVector *clipMask = psVectorAlloc(nSamples, PS_TYPE_VECTOR_MASK); // Mask for clipping 601 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, order); // Polynomial to fit 602 psVector *data = psVectorAlloc(numCols, PS_TYPE_F32); // Data to fit 603 604 psImage *corr = psImageAlloc(order + 1, numRows, PS_TYPE_F64); // Corrections applied 605 psImageInit(corr, NAN); 606 607 // CZW: 2011-11-30 608 // Define the vectors to hold the "x" and "y" slope trends. 609 // Briefly, the slope trend in the y-axis is a due to variations in the 0-th order term 610 // of the PATTERN.ROW fit between individual rows across the cell. Similarly, the 1-st 611 // order term of the PATTERN.ROW fit defines the trend in the x-axis (as that's what we 612 // are fitting with PATTERN.ROW in the first place). However, the thing we're trying to 613 // fix with PATTERN.ROW is the detector level bias wiggles. These should be overlaid on 614 // the true sky level. Therefore, simply applying the PATTERN.ROW correction will 615 // introduce cell-to-cell sky variations as these two trends are removed. To avoid this, 616 // We store the 0th and 1st order values used for each row, and then fit a polynomial to 617 // these results. By re-adding these systematic trends back, we can remove the row-to-row 618 // variations without improperly removing the real sky trend. 619 psVector *yaxisData = psVectorAlloc(numRows, PS_TYPE_F32); // Data to fit to the constant term 620 psVector *yaxisMask = psVectorAlloc(numRows, PS_TYPE_VECTOR_MASK); // Mask for rows with no fit 621 psVector *xaxisData = psVectorAlloc(numRows, PS_TYPE_F32); // Data to fit to the linear term 622 psVectorInit(yaxisMask, 0); 623 624 // validNmin is the minimum number of samples needed to measure the trend. 625 // this should be tunable, but let's try 5 - 10% 626 int validNmin = PS_MAX (nSamples * 0.1, order + 2); 627 628 for (int y = 0; y < numRows; y++) { 629 psVectorInit(clipMask, 0); 630 data = psImageRow(data, image, y); 631 int num = 0; // Number of good pixels 632 633 // if the unmasked pixels only span a small range in x then we cannot fit the 634 // 2nd order polynomial variations very well. Require a minimum fractional range 635 float validXmin = +1; 636 float validXmax = -1; 637 638 for (int sample = 0; sample < nSamples; sample ++) { 639 640 // store valid samples in the array to be sorted 641 float sampleArray[NPIX]; 642 int seq = 0; 643 for (int j = 0; j < NPIX; j++) { 644 int pix = sample * NPIX + j; // real pixel elements in x-dir 645 psAssert (pix >= 0, "invalid pix value"); 646 psAssert (pix < numCols, "invalid pix value"); 647 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][pix] & maskVal)) continue; 648 if (data->data.F32[pix] < lower || data->data.F32[pix] > upper) continue; 649 sampleArray[seq] = data->data.F32[pix]; // store the value to be sorted 650 seq ++; 651 } 652 if (seq < 1) { 653 clipMask->data.PS_TYPE_VECTOR_MASK_DATA[sample] = 0xFF; 654 yFit->data.F32[sample] = NAN; 655 continue; 656 } 657 // note that we are treating the x-coordinate as the center 658 // of the binned pixel group, even if some or most pixels have 659 // been masked. compared to the amplitude of the slope, this 660 // error is small 661 clipMask->data.PS_TYPE_VECTOR_MASK_DATA[sample] = 0; 662 validXmin = PS_MIN(xFit->data.F32[sample], validXmin); 663 validXmax = PS_MAX(xFit->data.F32[sample], validXmax); 664 num++; 665 666 // PSSORT operates on sampleArray (see define of macro SORT_SWAP above) 667 PSSORT (seq, SORT_COMPARE, SORT_SWAP, float); 668 669 int midPt = 0.5 * seq; 670 if (seq % 2 == 1) { psAssert (midPt >= 0, "invalid midPt"); } 671 if (seq % 2 == 0) { psAssert (midPt >= 1, "invalid midPt"); } 672 psAssert (midPt < NPIX, "invalid midPt"); 673 674 float medValue = (seq % 2) ? sampleArray[midPt] : 0.5*(sampleArray[midPt] + sampleArray[midPt-1]); 675 yFit->data.F32[sample] = medValue; 676 } 677 678 // If not enough points are valid, skip 679 if (num < validNmin) { 680 // Ignore this row in our subsequent fits, because the fit failed. 681 yaxisMask->data.PS_TYPE_VECTOR_MASK_DATA[y] = 0xFF; 682 continue; 683 } 684 // XXX does this need to be a clipped fit if we are clipping based on the median poisson noise? 685 if (!psVectorClipFitPolynomial1D(poly, clip, clipMask, 0xFF, yFit, NULL, xFit)) { 686 psWarning("Unable to fit polynomial to row %d", y); 687 psErrorClear(); 688 // Ignore this row in our subsequent fits, because the fit failed. 689 yaxisMask->data.PS_TYPE_VECTOR_MASK_DATA[y] = 0xFF; 690 continue; 691 } 692 // Store the results we found for this row. 693 yaxisData->data.F32[y] = poly->coeff[0]; 694 xaxisData->data.F32[y] = poly->coeff[1]; 695 psTrace("pattern",1,"%d %g %g\n",y,poly->coeff[0],poly->coeff[1]); 696 697 memcpy(corr->data.F64[y], poly->coeff, (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 698 psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector 699 if (!solution) { 700 psWarning("Unable to evaluate polynomial for row %d", y); 701 psErrorClear(); 702 yaxisMask->data.PS_TYPE_VECTOR_MASK_DATA[y] = 0xFF; 703 continue; 704 } 705 706 psAssert (solution->n == numCols, "oops"); 707 for (int x = 0; x < numCols; x++) { 708 image->data.F32[y][x] -= solution->data.F32[x]; 709 psTrace("pattern",5,"A: %d %d %g\n",x,y,solution->data.F32[x]); 710 } 711 psFree(solution); 712 } 713 714 // Put the global trends back that were removed by the PATTERN.ROW correction. 715 // Set up the indices for the polynomial 716 psVector *yaxisIndices = psVectorAlloc(numRows, PS_TYPE_F32); 717 norm = 2.0 / (float)numRows; 718 for (int y = 0; y < numRows; y++) { 719 yaxisIndices->data.F32[y] = y * norm - 1.0; 720 psTrace("psModules.detrend.pattern",10,"%d %f %f\n",y,yaxisIndices->data.F32[y],yaxisData->data.F32[y]); 721 } 722 723 // Fit the trend of the constant term, producing the y-axis global trend 724 psStatsInit(clip); 725 psPolynomial1D *yaxisPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1); // Polynomial to fit. 726 if (!psVectorClipFitPolynomial1D(yaxisPoly,clip,yaxisMask,0xFF,yaxisData, NULL, yaxisIndices)) { 727 psWarning("Unable to fit polynomial to y-axis trend"); 728 psErrorClear(); 729 // If we've failed, we need to do something, so add back in the background level, and 730 // expect that the final image will have background mismatches. 731 for (int y = 0; y < numRows; y++) { 732 for (int x = 0; x < numCols; x++) { 733 image->data.F32[y][x] += background; 734 } 735 corr->data.F64[y][0] -= background; 736 } 737 } else { 738 psVector *solution = psPolynomial1DEvalVector(yaxisPoly,yaxisIndices); 739 if (!solution) { 740 psWarning("Unable to evaluate polynomial"); 741 psErrorClear(); 742 // If we've failed, we need to do something, so add back in the background level, and 743 // expect that the final image will have background mismatches. 744 for (int y = 0; y < numRows; y++) { 745 for (int x = 0; x < numCols; x++) { 746 image->data.F32[y][x] += background; 747 } 748 corr->data.F64[y][0] -= background; 749 } 750 } else { 751 psAssert (solution->n == numRows, "oops"); 752 for (int y = 0; y < numRows; y++) { 753 for (int x = 0; x < numCols; x++) { 754 image->data.F32[y][x] += solution->data.F32[y]; 755 // XXX EAM : this was [x], which is wrong 756 psTrace("pattern",5,"B: %d %d %g\n",x,y,solution->data.F32[y]); 757 } 758 corr->data.F64[y][0] -= solution->data.F32[y]; 759 } 760 } 761 psFree(solution); 762 } 763 764 // Fit the trend of the linear term, producing the x-axis global trend 765 // We can use the same mask vector, as the same rows failed the row-fit earlier. 766 psStatsInit(clip); 767 psPolynomial1D *xaxisPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1); // Polynomial to fit. 768 if (!psVectorClipFitPolynomial1D(xaxisPoly,clip,yaxisMask,0xFF,xaxisData, NULL, yaxisIndices)) { 769 psWarning("Unable to fit polynomial to x-axis trend"); 770 psErrorClear(); 771 } else { 772 psVector *solution = psPolynomial1DEvalVector(xaxisPoly,yaxisIndices); 773 if (!solution) { 774 psWarning("Unable to evaluate polynomial"); 775 psErrorClear(); 776 } else { 777 psAssert (solution->n == numRows, "oops"); 778 for (int y = 0; y < numRows; y++) { 779 for (int x = 0; x < numCols; x++) { 780 image->data.F32[y][x] += solution->data.F32[y] * indices->data.F32[x]; 781 // XXX EAM : this was set to [x] which is wrong (numCols > numRows) 782 psTrace("pattern",5,"C: %d %d %g %g\n",x,y,solution->data.F32[y],indices->data.F32[x]); 783 } 784 corr->data.F64[y][1] -= solution->data.F32[y] ; 785 } 786 } 787 psFree(solution); 788 } 789 psFree(yaxisPoly); 790 psFree(xaxisPoly); 791 psFree(yaxisIndices); 792 psFree(yaxisMask); 793 psFree(yaxisData); 794 psFree(xaxisData); 795 796 psMetadataAddImage(ro->analysis, PS_LIST_TAIL, PM_PATTERN_ROW_CORRECTION, PS_META_REPLACE, 797 "Pattern row correction", corr); 798 psFree(corr); 799 800 psFree(indices); 801 psFree(xFit); 802 psFree(yFit); 264 803 psFree(clip); 265 804 psFree(clipMask); … … 1316 1855 return true; 1317 1856 } 1857 -
trunk/psModules/src/detrend/pmPatternIO.c
r26923 r41892 8 8 #include "pmFPAview.h" 9 9 #include "pmFPAfile.h" 10 #include "pmFPAUtils.h" 10 11 #include "pmFPAfileFitsIO.h" 11 12 #include "pmFPAHeader.h" … … 452 453 return pmReadoutReadPattern(readout, file->fits); 453 454 } 455 456 /**************** PatternRowAmp(litude) I/O *************************/ 457 458 bool pmPatternRowAmpRead (const pmFPAview *view, pmFPAfile *file, const pmConfig *config) 459 { 460 // read the full model in one pass: require the level to be FPA 461 if (view->chip != -1) { 462 psError(PS_ERR_IO, false, "Pattern Row Amplitude must be read at the FPA level"); 463 return false; 464 } 465 466 if (!pmPatternRowAmpReadFPA (file)) { 467 psError(PS_ERR_IO, false, "Failed to read Pattern Row Amplitude for fpa"); 468 return false; 469 } 470 return true; 471 } 472 473 // read in all chip-level Pattern Row Amplitude data for this FPA 474 bool pmPatternRowAmpReadFPA (pmFPAfile *file) { 475 476 if (!pmPatternRowAmpReadChips (file)) { 477 psError(PS_ERR_IO, false, "Failed to read Pattern Row Amplitude for chips"); 478 return false; 479 } 480 481 return true; 482 } 483 484 // read the set of tables, one for each chip 485 bool pmPatternRowAmpReadChips (pmFPAfile *file) { 486 487 bool haveData, status; 488 489 // loop over the extensions 490 // for each extension, use the extname (eg, XY01.ptn) to assign to a chip 491 492 // move to the start of the file 493 haveData = psFitsMoveExtNum (file->fits, 1, false); 494 if (!haveData) { 495 psError(PS_ERR_IO, false, "Failed to read even the first extension?"); 496 return false; 497 } 498 499 int nGood = 0; 500 int nTotal = 0; 501 while (haveData) { 502 503 // load the header 504 psMetadata *header = psFitsReadHeader(NULL, file->fits); // The FITS header 505 if (!header) psAbort("cannot read model header"); 506 507 // load the full model in one shot 508 psArray *model = psFitsReadTable (file->fits); 509 if (!model) psAbort("cannot read model"); 510 511 // determine the chip: 512 char *extname = psMetadataLookupStr (&status, header, "EXTNAME"); 513 psLogMsg ("psModules.detrend", 8, "read %ld rows from Pattern Row Amplitude file, extname %s\n", model->n, extname); 514 nTotal += model->n; 515 516 // I expect to find a name of the form: chipName.ptn (eg, XY01.ptn) 517 // where chipName like 'XY01' 518 psAssert (strlen(extname) == 8, "invalid extension %s", extname); 519 psAssert (extname[5] == 'p', "invalid extension %s", extname); 520 psAssert (extname[6] == 't', "invalid extension %s", extname); 521 psAssert (extname[7] == 'n', "invalid extension %s", extname); 522 523 char chipName[5]; 524 strncpy (chipName, extname, 4); 525 chipName[4] = 0; 526 527 pmChip *chip = pmConceptsChipFromName (file->fpa, chipName); 528 if (!chip) psAbort ("invalid chip?"); 529 530 // parse the model entries 531 for (int i = 0; i < model->n; i++) { 532 psMetadata *row = model->data[i]; 533 psAssert (row, "missing model row"); 534 535 char *cellName = psMetadataLookupStr(&status, row, "CELL_NAME"); 536 if (!cellName) continue; 537 538 float amplitude = psMetadataLookupF32(&status, row, "VALUE_MEDIAN"); 539 540 int cellNumber = pmChipFindCell (chip, cellName); 541 psAssert ((cellNumber >=0) && (cellNumber < chip->cells->n), "invalid cell number"); 542 543 pmCell *cell = chip->cells->data[cellNumber]; 544 if (!cell) continue; 545 546 psAssert (cell->analysis, "oops"); 547 548 psMetadataAddF32 (cell->analysis, PS_LIST_TAIL, "PTN.ROW.AMP", PS_META_REPLACE, "", amplitude); 549 nGood ++; 550 } 551 552 psFree (model); 553 psFree (header); 554 555 // move to the next extension 556 haveData = psFitsMoveExtNum (file->fits, 1, true); 557 } 558 psLogMsg ("psModules.detrend", 4, "read %d of %d rows from Pattern Row Amplitude file\n", nGood, nTotal); 559 560 return true; 561 } -
trunk/psModules/src/detrend/pmPatternIO.h
r26893 r41892 35 35 ); 36 36 37 38 bool pmPatternRowAmpRead (const pmFPAview *view, pmFPAfile *file, const pmConfig *config); 39 bool pmPatternRowAmpReadFPA (pmFPAfile *file); 40 bool pmPatternRowAmpReadChips (pmFPAfile *file); 41 37 42 #endif -
trunk/psModules/src/imcombine/pmStack.c
r36710 r41892 756 756 // *goodMask &= mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn]; // save the mask bits still used 757 757 // check for set bits and increment counter as appropriate 758 // count the number of times a given mask bit is set in the input pixels. 759 // NOTE: since we have explicitly skipped the pixels with any bad bits, these are only 760 // the suspect bits (nGoodBits is a bit of a misnomer: it is more like 'nSuspectBitsForGoodInputs' 758 761 { 759 762 psImageMaskType value = 0x0001; … … 961 964 962 965 // KMM values; 963 float Punimodal = 1.0, KMMmean = NAN,KMMsigma = NAN,KMMpi = NAN;966 float Punimodal = 1.0, KMMmean = NAN, KMMsigma = NAN, KMMpi = NAN; 964 967 int KMM_MINIMUM_INPUTS = 6; 965 968 bool useKMM = false; … … 1510 1513 } 1511 1514 1515 # define MIN_GOOD_PERCENTILE 2 1516 bool pmStackCombineByPercentile( 1517 pmReadout *combined, 1518 psArray *stackData, 1519 psF64 minRange, 1520 psF64 maxRange, 1521 psImageMaskType badMaskBits, // treat these bits as 'bad' 1522 psImageMaskType suspectMaskBits, // treat these bits as 'suspect' 1523 psImageMaskType blankMaskBits // use this mask value for pixels missing input data (distinguish between Ninput = 0 and Ngood = 0?) 1524 ) { 1525 int minInputCols, maxInputCols, minInputRows, maxInputRows; // Smallest and largest values to combine 1526 int xSize, ySize; // Size of the output image 1527 1528 // we need to copy the readouts to their own array for validation 1529 psArray *stackReadouts = psArrayAlloc(stackData->n); 1530 for (int i = 0; i < stackData->n; i++) { 1531 pmStackData *data = stackData->data[i]; // Stack data for this input 1532 pmReadout *ro = data->readout; // Readout of interest 1533 stackReadouts->data[i] = psMemIncrRefCounter(ro); 1534 } 1535 1536 if (!pmReadoutStackValidate(&minInputCols, &maxInputCols, &minInputRows, &maxInputRows, &xSize, &ySize, stackReadouts)) { 1537 psError(psErrorCodeLast(), false, "Input stack is not valid."); 1538 psFree(stackReadouts); 1539 return false; 1540 } 1541 psFree(stackReadouts); 1542 1543 psVector *pixelData = psVectorAlloc(stackData->n, PS_TYPE_F32); 1544 psVector *pixelMask = psVectorAlloc(stackData->n, PS_TYPE_VECTOR_MASK); 1545 1546 for (int y = minInputRows; y < maxInputRows; y++) { 1547 for (int x = minInputCols; x < maxInputCols; x++) { 1548 1549 int nGood = 0; 1550 for (int i = 0; i < stackData->n; i++) { 1551 1552 pmStackData *data = stackData->data[i]; // Stack data for this input 1553 pmReadout *ro = data->readout; // Readout of interest 1554 psImage *image = ro->image; 1555 psImage *mask = ro->mask; 1556 1557 int xIn = x - data->readout->col0; 1558 int yIn = y - data->readout->row0; // Coordinates on input readout 1559 1560 if (!isfinite(image->data.F32[yIn][xIn])) continue; 1561 if (fabs(image->data.F32[yIn][xIn]) > 1e5) continue; 1562 // XXX need to test the input mask as well here 1563 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & badMaskBits); 1564 1565 // XXX save the count of suspect bits 1566 1567 # if (0) 1568 // count the number of times a given mask bit is set in the input pixels. 1569 // NOTE: since we have explicitly skipped the pixels with any bad bits, these are only 1570 // the suspect bits (nGoodBits is a bit of a misnomer: it is more like 'nSuspectBitsForGoodInputs' 1571 if (1) { 1572 psImageMaskType value = 0x0001; 1573 for (int nbit = 0; nbit < 16; nbit ++) { 1574 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & value) { 1575 // XXX nGoodBits[nbit] ++; 1576 } 1577 value <<= 1; 1578 } 1579 } 1580 # endif 1581 1582 pixelData->data.F32[nGood] = image->data.F32[yIn][xIn]; 1583 nGood ++; 1584 } 1585 pixelData->n = nGood; 1586 psVectorSortInPlace (pixelData); 1587 1588 if (nGood < MIN_GOOD_PERCENTILE) { 1589 combined->image->data.F32[y][x] = NAN; 1590 combined->variance->data.F32[y][x] = NAN; 1591 combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 1; 1592 continue; 1593 } 1594 1595 # if (0) 1596 # define SUSPECT_FRACTION 0.65 1597 // set the mask bits if nGoodBits[i] > f*numGood 1598 if (0) { 1599 psImageMaskType value = 0x0001; 1600 for (int nbit = 0; nbit < 16; nbit ++) { 1601 if (nGoodBits[nbit] > SUSPECT_FRACTION*numGood) { 1602 *goodMask |= value; 1603 } 1604 value <<= 1; 1605 } 1606 } 1607 # endif 1608 1609 int Ns = MIN(MAX(0, minRange * nGood),nGood); // e.g., 0.1 * 50 = 5 1610 int Ne = MIN(MAX(0, maxRange * nGood),nGood); // e.g., 0.9 * 50 = 45 1611 int Npt = Ne - Ns; 1612 1613 float sum = 0.0; 1614 for (int n = Ns; n < Ne; n++) { 1615 sum += pixelData->data.F32[n]; 1616 } 1617 float mean = sum / (float) Npt; 1618 1619 float varSum = 0.0; 1620 for (int n = Ns; n < Ne; n++) { 1621 varSum += SQ(pixelData->data.F32[n] - mean); 1622 } 1623 // variance on the mean (stdev / sqrt(N))^2 1624 float varValue = varSum / (Npt - 1) / Npt; 1625 1626 // XXX this is probably not the correct variance to save 1627 // the predicted variance should be the 1 / sum (1/var) 1628 1629 combined->image->data.F32[y][x] = mean; 1630 combined->variance->data.F32[y][x] = varValue; 1631 combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0; 1632 } 1633 } 1634 1635 psFree(pixelData); 1636 psFree(pixelMask); 1637 1638 return (true); 1639 } 1640 1512 1641 /// Stack input images 1513 1642 bool pmStackCombine( … … 1644 1773 expweight = expmaps->variance; 1645 1774 } 1646 1647 /* // Pre-reject inputs using KMM bimodality test. */1648 /* if (1) { */1649 /* /\* KMMRejectUnpopular(input,x,y); *\/ */1650 /* rejection = true; */1651 /* } */1652 1775 1653 1776 // Set up rejection list … … 1660 1783 for (int y = minInputRows; y < maxInputRows; y++) { 1661 1784 for (int x = minInputCols; x < maxInputCols; x++) { 1785 // this is only for TESTING: 1662 1786 CHECKPIX(x, y, "Combining pixel %d,%d: %x %x %f %f %f %f %d %d %d\n", x, y, badMaskBits, blankMaskBits, iter, rej, sys, olympic, useVariance, safe, rejection); 1663 1664 /* // Pre-reject inputs using KMM bimodality test. */1665 /* if (1) { */1666 /* KMMRejectUnpopular(input,x,y); */1667 /* /\* rejection = true; *\/ */1668 /* } */1669 /* else { */1670 /* KMMRejectBright(input,x,y); */1671 /* } */1672 1673 #ifdef TESTING1674 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) {1675 fprintf (stderr, "combine\n");1676 }1677 # endif1678 1787 1679 1788 psVector *reject = NULL; // Images to reject for this pixel -
trunk/psModules/src/imcombine/pmStack.h
r36710 r41892 47 47 ); 48 48 49 bool pmStackCombineByPercentile( 50 pmReadout *combined, 51 psArray *input, 52 psF64 minRange, 53 psF64 maxRange, 54 psImageMaskType badMaskBits, // treat these bits as 'bad' 55 psImageMaskType suspectMaskBits, // treat these bits as 'suspect' 56 psImageMaskType blankMaskBits // use this mask value for pixels missing input data (distinguish between Ninput = 0 and Ngood = 0?) 57 ); 58 49 59 /// Stack input images 50 60 bool pmStackCombine(pmReadout *combined,///< Combined readout (output) -
trunk/psModules/src/objects/pmSourceIO_CMF.c.in
r38114 r41892 57 57 // followed by a zero-size matrix, followed by the table data 58 58 59 bool pmSourcesWrite_CMF_@CMFMODE@ (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe) 59 /** this file is used to generate c-code for a number of different formats. the perl program 60 ** 'mksource.pl' reads this template file and generates an output file for one of the named 61 ** formats, e.g., PS1_V1 or PS1_DV4 (see list in mksource.pl). 62 63 ** Any instances of the word @CMFMODE@ are replaced by the named version of the format. 64 65 ** Any line which starts with a command of the form: @COMMAND[,COMMAND...]@ is kept or removed 66 ** from the output c-code depending on the commands. These may be: ALL (lines are kept for 67 ** all formats) or the name of a format. A line with just a plain format will be kept only 68 ** for that format. The format name may be optionally proceded by >, <, <=, >=, ! or =. In 69 ** these cases, the line is kept if the format is greater / lesser / not the same, etc as the 70 ** listed format. The sequence of formats is defined for series (V, SV, DV) in mksource.pl so 71 ** that, e.g., >PS1_V3 would include e.g., PS1_V4 and PS1_V5, but not PS1_DV4. The number in 72 ** a series may be replaced with ? to stand for the full set. The format 73 ** commands may be grouped on a line separated by commas. Note that only ! (not) is 74 ** restrictive: only this rule will reduce the number of matches. So for example, 75 ** @ALL,<PS1_DV3@ will have the effect of @ALL@ since any format >= PS1_DV3 will be matched by 76 ** ALL. But @ALL,!PS1_DV3@ will generate a line for any format except PS1_DV3. 77 78 **/ 79 80 bool pmSourcesWrite_CMF_@CMFMODE@_New (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe) 60 81 { 82 // fprintf (stderr, "writing with %s\n", __func__); 61 83 PS_ASSERT_PTR_NON_NULL(fits, false); 62 84 PS_ASSERT_PTR_NON_NULL(sources, false); 63 85 PS_ASSERT_PTR_NON_NULL(extname, false); 64 65 psArray *table;66 psMetadata *row;67 86 68 87 pmChip *chip = readout->parent->parent; … … 73 92 pmSource *source = (pmSource *) sources->data[0]; 74 93 if (source->seq == -1) { 75 // let's write these out in S/N order76 sources = psArraySort (sources, pmSourceSortByFlux);94 // let's write these out in S/N order 95 sources = psArraySort (sources, pmSourceSortByFlux); 77 96 } else { 78 sources = psArraySort (sources, pmSourceSortBySeq); 79 } 80 } 81 82 table = psArrayAllocEmpty (sources->n); 97 sources = psArraySort (sources, pmSourceSortBySeq); 98 } 99 } 83 100 84 101 float magOffset; … … 88 105 pmSourceOutputsCommonValues (&magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader); 89 106 107 // before we can generate the table structure, we need to know if certain fields were measured. 108 // this information is not available a priori, so we need to check all sources 109 110 bool haveLensingOBJsmear = false; 111 bool haveLensingOBJshear = false; 112 bool haveLensingPSFsmear = false; 113 bool haveLensingPSFshear = false; 114 bool haveLensingPSF = false; 115 116 for (int i = 0; (i < sources->n) && !haveLensingOBJsmear && !haveLensingOBJshear && !haveLensingPSFsmear && !haveLensingPSFshear && !haveLensingPSF; i++) { 117 // this is the source associated with this image 118 pmSource *thisSource = sources->data[i]; 119 120 // this is the "real" version of this source 121 pmSource *source = thisSource->parent ? thisSource->parent : thisSource; 122 123 if (source->lensingOBJ && source->lensingOBJ->smear) haveLensingOBJsmear = true; 124 if (source->lensingOBJ && source->lensingOBJ->shear) haveLensingOBJshear = true; 125 if (source->lensingPSF && source->lensingPSF->smear) haveLensingPSFsmear = true; 126 if (source->lensingPSF && source->lensingPSF->shear) haveLensingPSFshear = true; 127 if (source->lensingPSF ) haveLensingPSF = true; 128 } 129 130 /************ generate the table columns *****************/ 131 132 // before we allocate the table, generate an empty array of table columns and generate them 133 psArray *tableColumns = psArrayAllocEmpty (100); 134 135 // add the named / typed columns to the collection of columns 136 @ALL@ psFitsTableColumnAdd (tableColumns, "IPP_IDET", PS_DATA_U32); // "IPP detection identifier index" 137 @ALL@ psFitsTableColumnAdd (tableColumns, "X_PSF", PS_DATA_F32); // "PSF x coordinate" 138 @ALL@ psFitsTableColumnAdd (tableColumns, "Y_PSF", PS_DATA_F32); // "PSF y coordinate" 139 @ALL@ psFitsTableColumnAdd (tableColumns, "X_PSF_SIG", PS_DATA_F32); // "Sigma in PSF x coordinate" 140 @ALL@ psFitsTableColumnAdd (tableColumns, "Y_PSF_SIG", PS_DATA_F32); // "Sigma in PSF y coordinate" 141 142 // NOTE: pre-PS1_V2, we only reported RA & DEC in floats for reference, not precision 143 @PS1_V1@ psFitsTableColumnAdd (tableColumns, "RA_PSF", PS_DATA_F32); // "PSF RA coordinate (degrees)" 144 @PS1_V1@ psFitsTableColumnAdd (tableColumns, "DEC_PSF", PS_DATA_F32); // "PSF DEC coordinate (degrees)" 145 146 @ALL@ psFitsTableColumnAdd (tableColumns, "POSANGLE", PS_DATA_F32); // "position angle at source (degrees)" 147 @ALL@ psFitsTableColumnAdd (tableColumns, "PLTSCALE", PS_DATA_F32); // "plate scale at source (arcsec/pixel)" 148 @ALL@ psFitsTableColumnAdd (tableColumns, "PSF_INST_MAG", PS_DATA_F32); // "PSF fit instrumental magnitude" 149 @ALL@ psFitsTableColumnAdd (tableColumns, "PSF_INST_MAG_SIG", PS_DATA_F32); // "Sigma of PSF instrumental magnitude" 150 151 @ALL,!PS1_V1,!PS1_V2@ psFitsTableColumnAdd (tableColumns, "PSF_INST_FLUX", PS_DATA_F32); // "PSF fit instrumental flux (counts)" 152 @ALL,!PS1_V1,!PS1_V2@ psFitsTableColumnAdd (tableColumns, "PSF_INST_FLUX_SIG", PS_DATA_F32); // "Sigma of PSF instrumental flux" 153 154 @ALL@ psFitsTableColumnAdd (tableColumns, "AP_MAG", PS_DATA_F32); // "magnitude in standard aperture" 155 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "AP_MAG_RAW", PS_DATA_F32); // "magnitude in reported aperture" 156 @ALL@ psFitsTableColumnAdd (tableColumns, "AP_MAG_RADIUS", PS_DATA_F32); // "radius used for aperture mags" 157 @>PS1_DV1,>PS1_V3,>PS1_SV1@ psFitsTableColumnAdd (tableColumns, "AP_FLUX", PS_DATA_F32); // "instrumental flux in standard aperture" 158 @>PS1_DV1,>PS1_V3,>PS1_SV1@ psFitsTableColumnAdd (tableColumns, "AP_FLUX_SIG", PS_DATA_F32); // "aperture flux error" 159 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psFitsTableColumnAdd (tableColumns, "AP_NPIX", PS_DATA_S32); // "aperture unmasked pixels" 160 161 @<PS1_V3,PS1_SV1,PS1_DV?@ psFitsTableColumnAdd (tableColumns, "PEAK_FLUX_AS_MAG", PS_DATA_F32); // "Peak flux expressed as magnitude" 162 163 @ALL@ psFitsTableColumnAdd (tableColumns, "CAL_PSF_MAG", PS_DATA_F32); // "PSF Magnitude using supplied calibration" 164 @ALL@ psFitsTableColumnAdd (tableColumns, "CAL_PSF_MAG_SIG", PS_DATA_F32); // "measured scatter of zero point calibration" 165 166 // NOTE: RA & DEC (both double) need to be on an 8-byte boundary... 167 @ALL,!PS1_V1@ psFitsTableColumnAdd (tableColumns, "RA_PSF", PS_DATA_F64); // "PSF RA coordinate (degrees)" 168 @ALL,!PS1_V1@ psFitsTableColumnAdd (tableColumns, "DEC_PSF", PS_DATA_F64); // "PSF DEC coordinate (degrees)" 169 170 @>=PS1_V3,>PS1_SV1@ psFitsTableColumnAdd (tableColumns, "PEAK_FLUX_AS_MAG", PS_DATA_F32); // "Peak flux expressed as magnitude" 171 @ALL@ psFitsTableColumnAdd (tableColumns, "SKY", PS_DATA_F32); // "Sky level" 172 @ALL@ psFitsTableColumnAdd (tableColumns, "SKY_SIGMA", PS_DATA_F32); // "Sigma of sky level" 173 @ALL@ psFitsTableColumnAdd (tableColumns, "PSF_CHISQ", PS_DATA_F32); // "Chisq of PSF-fit" 174 @ALL@ psFitsTableColumnAdd (tableColumns, "CR_NSIGMA", PS_DATA_F32); // "Nsigma deviations from PSF to CF" 175 @ALL@ psFitsTableColumnAdd (tableColumns, "EXT_NSIGMA", PS_DATA_F32); // "Nsigma deviations from PSF to EXT" 176 177 // PSF shape parameters: 178 @ALL@ psFitsTableColumnAdd (tableColumns, "PSF_MAJOR", PS_DATA_F32); // "PSF width (major axis)" 179 @ALL@ psFitsTableColumnAdd (tableColumns, "PSF_MINOR", PS_DATA_F32); // "PSF width (minor axis)" 180 @ALL@ psFitsTableColumnAdd (tableColumns, "PSF_THETA", PS_DATA_F32); // "PSF orientation angle" 181 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psFitsTableColumnAdd (tableColumns, "PSF_CORE", PS_DATA_F32); // "k term if defined" 182 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psFitsTableColumnAdd (tableColumns, "PSF_FWHM_MAJ", PS_DATA_F32); // "PSF FWHM (major axis)" 183 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psFitsTableColumnAdd (tableColumns, "PSF_FWHM_MIN", PS_DATA_F32); // "PSF FWHM (minor axis)" 184 185 // psf data quality 186 @ALL@ psFitsTableColumnAdd (tableColumns, "PSF_QF", PS_DATA_F32); // "PSF coverage/quality factor (bad)" 187 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "PSF_QF_PERFECT", PS_DATA_F32); // "PSF coverage/quality factor (poor)" 188 @ALL@ psFitsTableColumnAdd (tableColumns, "PSF_NDOF", PS_DATA_S32); // "degrees of freedom" 189 @ALL@ psFitsTableColumnAdd (tableColumns, "PSF_NPIX", PS_DATA_S32); // "number of pixels in fit" 190 191 @ALL@ psFitsTableColumnAdd (tableColumns, "MOMENTS_XX", PS_DATA_F32); // "second moments (X^2)" 192 @ALL@ psFitsTableColumnAdd (tableColumns, "MOMENTS_XY", PS_DATA_F32); // "second moments (X*Y)" 193 @ALL@ psFitsTableColumnAdd (tableColumns, "MOMENTS_YY", PS_DATA_F32); // "second moments (Y*Y)" 194 @>PS1_V2,PS1_SV?@ psFitsTableColumnAdd (tableColumns, "MOMENTS_M3C", PS_DATA_F32); // "third momemt cos theta" 195 @>PS1_V2,PS1_SV?@ psFitsTableColumnAdd (tableColumns, "MOMENTS_M3S", PS_DATA_F32); // "third momemt sin theta" 196 @>PS1_V2,PS1_SV?@ psFitsTableColumnAdd (tableColumns, "MOMENTS_M4C", PS_DATA_F32); // "fourth momemt cos theta" 197 @>PS1_V2,PS1_SV?@ psFitsTableColumnAdd (tableColumns, "MOMENTS_M4S", PS_DATA_F32); // "fourth momemt sin theta" 198 199 // Lensing parameters are only written if they are measured 200 if (haveLensingOBJsmear) { 201 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X11_SM_OBJ", PS_DATA_F32); // "smear polarizability element (objects)" 202 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X12_SM_OBJ", PS_DATA_F32); // "smear polarizability element (objects)" 203 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X22_SM_OBJ", PS_DATA_F32); // "smear polarizability element (objects)" 204 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E1_SM_OBJ", PS_DATA_F32); // "smear polarizability element (objects)" 205 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E2_SM_OBJ", PS_DATA_F32); // "smear polarizability element (objects)" 206 } 207 if (haveLensingOBJshear) { 208 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X11_SH_OBJ", PS_DATA_F32); // "shear polarizability element (objects)" 209 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X12_SH_OBJ", PS_DATA_F32); // "shear polarizability element (objects)" 210 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X22_SH_OBJ", PS_DATA_F32); // "shear polarizability element (objects)" 211 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E1_SH_OBJ", PS_DATA_F32); // "shear polarizability element (objects)" 212 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E2_SH_OBJ", PS_DATA_F32); // "shear polarizability element (objects)" 213 } 214 if (false) { 215 // do not bother to save these as they are equivalent to Mxx,Mxy,Myy above 216 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E1_OBJ", PS_DATA_F32); // "shear polarizability element (objects)" 217 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E2_OBJ", PS_DATA_F32); // "shear polarizability element (objects)" 218 } 219 220 if (haveLensingPSFsmear) { 221 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X11_SM_PSF", PS_DATA_F32); // "smear polarizability element (PSFs)" 222 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X12_SM_PSF", PS_DATA_F32); // "smear polarizability element (PSFs)" 223 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X22_SM_PSF", PS_DATA_F32); // "smear polarizability element (PSFs)" 224 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E1_SM_PSF", PS_DATA_F32); // "smear polarizability element (PSFs)" 225 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E2_SM_PSF", PS_DATA_F32); // "smear polarizability element (PSFs)" 226 } 227 if (haveLensingPSFshear) { 228 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X11_SH_PSF", PS_DATA_F32); // "shear polarizability element (PSFs)" 229 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X12_SH_PSF", PS_DATA_F32); // "shear polarizability element (PSFs)" 230 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_X22_SH_PSF", PS_DATA_F32); // "shear polarizability element (PSFs)" 231 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E1_SH_PSF", PS_DATA_F32); // "shear polarizability element (PSFs)" 232 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E2_SH_PSF", PS_DATA_F32); // "shear polarizability element (PSFs)" 233 } 234 if (haveLensingPSF) { 235 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E1_PSF", PS_DATA_F32); // "shear polarizability element (PSFs)" 236 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "LENS_E2_PSF", PS_DATA_F32); // "shear polarizability element (PSFs)" 237 } 238 239 // if lensing params exist also include the backmapped chipID and chip coordinates 240 if (haveLensingPSF) { 241 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "SRC_CHIP_NUM", PS_DATA_S16); // "id of warp input chip" 242 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "SRC_CHIP_X", PS_DATA_S16); // "x coord in warp input chip" 243 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "SRC_CHIP_Y", PS_DATA_S16); // "y coord in warp input chip" 244 @>PS1_V4@ psFitsTableColumnAdd (tableColumns, "PADDING3", PS_DATA_S16); // "more padding" 245 } 246 247 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "MOMENTS_R1", PS_DATA_F32); // "first radial moment" 248 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "MOMENTS_RH", PS_DATA_F32); // "half radial moment" 249 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "KRON_FLUX", PS_DATA_F32); // "Kron Flux (in 2.5 R1)" 250 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "KRON_FLUX_ERR", PS_DATA_F32); // "Kron Flux Error" 251 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "KRON_FLUX_INNER", PS_DATA_F32); // "Kron Flux (in 1.0 R1)" 252 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "KRON_FLUX_OUTER", PS_DATA_F32); // "Kron Flux (in 4.0 R1)" 253 254 @>PS1_V3@ psFitsTableColumnAdd (tableColumns, "SKY_LIMIT_RAD", PS_DATA_F32); // "Radius where object hits sky" 255 @>PS1_V3@ psFitsTableColumnAdd (tableColumns, "SKY_LIMIT_FLUX", PS_DATA_F32); // "Flux / pix where object hits sky" 256 @>PS1_V3@ psFitsTableColumnAdd (tableColumns, "SKY_LIMIT_SLOPE", PS_DATA_F32); // "d(Flux/pix)/dRadius where object hits sky" 257 258 @>PS1_DV4@ psFitsTableColumnAdd (tableColumns, "SRC_CHIP_NUM", PS_DATA_S16); // "id of warp input chip" 259 @>PS1_DV4@ psFitsTableColumnAdd (tableColumns, "SRC_CHIP_X", PS_DATA_S16); // "x coord in warp input chip" 260 @>PS1_DV4@ psFitsTableColumnAdd (tableColumns, "SRC_CHIP_Y", PS_DATA_S16); // "y coord in warp input chip" 261 @>PS1_DV4@ psFitsTableColumnAdd (tableColumns, "PADDING3", PS_DATA_S16); // "more padding" 262 263 @PS1_DV?@ psFitsTableColumnAdd (tableColumns, "DIFF_NPOS", PS_DATA_S32); // "nPos (n pix > 3 sigma)" 264 @PS1_DV?@ psFitsTableColumnAdd (tableColumns, "DIFF_FRATIO", PS_DATA_F32); // "fPos / (fPos + fNeg)" 265 @PS1_DV?@ psFitsTableColumnAdd (tableColumns, "DIFF_NRATIO_BAD", PS_DATA_F32); // "nPos / (nPos + nNeg)" 266 @PS1_DV?@ psFitsTableColumnAdd (tableColumns, "DIFF_NRATIO_MASK", PS_DATA_F32); // "nPos / (nPos + nMask)" 267 @PS1_DV?@ psFitsTableColumnAdd (tableColumns, "DIFF_NRATIO_ALL", PS_DATA_F32); // "nPos / (nGood + nMask + nBad)" 268 269 @>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "DIFF_R_P", PS_DATA_F32); // "distance to positive match source" 270 @>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "DIFF_SN_P", PS_DATA_F32); // "signal-to-noise of pos match src" 271 @>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "DIFF_R_M", PS_DATA_F32); // "distance to negative match source" 272 @>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "DIFF_SN_M", PS_DATA_F32); // "signal-to-noise of neg match src" 273 274 @ALL@ psFitsTableColumnAdd (tableColumns, "FLAGS", PS_DATA_U32); // "psphot analysis flags" 275 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableColumnAdd (tableColumns, "FLAGS2", PS_DATA_U32); // "psphot analysis flags" 276 @PS1_V3,PS1_SV2@ psFitsTableColumnAdd (tableColumns, "PADDING2", PS_DATA_S32); // "more padding" 277 @ALL@ psFitsTableColumnAdd (tableColumns, "N_FRAMES", PS_DATA_U16); // "Number of frames overlapping source center" 278 279 @ALL@ psFitsTableColumnAdd (tableColumns, "PADDING", PS_DATA_S16); // "more padding" 280 281 // note that this definition is inconsistent with the definition in 282 // Ohana/src/libautocode/def. This version creates a table with data not 283 // properly aligned with the 8-byte boundaries. The structure defined by 284 // libautocode does this, but has a different order of elements (and adds 285 // padding2 to fix things). We have generated may files with PS1_SV1 as is, so 286 // I'll leave it. But in future a PS1_SV2 should be forced to match 287 // libautocode. Note that addstar knows to detect the alternate version of 288 // PS1_SV1 and correctly interpret its fields. 289 290 // EXT_NSIGMA will be NAN if: 1) contour ellipse is imaginary; 2) source is not 291 // subtracted 292 293 // CR_NSIGMA will be NAN if: 1) source is not subtracted; 2) source is on the image 294 // edge; 3) any pixels in the 3x3 peak region are masked; 295 296 // generate an FITS table using the array of columns defined above, with space for all rows 297 psFitsTable *table = psFitsTableCreate (tableColumns, sources->n); 298 299 /************ write the data to the table *****************/ 300 90 301 // we write out PSF-fits for all sources, regardless of quality. the source flags tell us the state 91 302 // by the time we call this function, all values should be assigned. let's use asserts to be sure in some cases. 92 303 for (int i = 0; i < sources->n; i++) { 93 // this is the source associated with this image304 // this is the source associated with this image 94 305 pmSource *thisSource = sources->data[i]; 95 306 96 // this is the "real" version of this source97 pmSource *source = thisSource->parent ? thisSource->parent : thisSource;307 // this is the "real" version of this source 308 pmSource *source = thisSource->parent ? thisSource->parent : thisSource; 98 309 99 310 // If source->seq is -1, source was generated in this analysis. If source->seq is … … 102 313 // generated on Alloc, and would thus be wrong for read in sources. 103 314 if (source->seq == -1) { 104 source->seq = i; 105 } 106 107 // set the 'best' values for various output fields: 108 pmSourceOutputs outputs; 109 pmSourceOutputsSetValues (&outputs, source, chip, fwhmMajor, fwhmMinor, magOffset); 110 111 pmSourceOutputsMoments moments; 112 pmSourceOutputsSetMoments (&moments, source); 113 114 @PS1_DV?@ pmSourceDiffStats diffStats; 115 @PS1_DV?@ pmSourceDiffStatsInit(&diffStats); 116 @PS1_DV?@ if (source->diffStats) { 117 @PS1_DV?@ diffStats = *source->diffStats; 118 @PS1_DV?@ } 119 120 row = psMetadataAlloc (); 315 source->seq = i; 316 } 317 318 // set the 'best' values for various output fields: 319 pmSourceOutputs outputs; 320 pmSourceOutputsSetValues (&outputs, source, chip, fwhmMajor, fwhmMinor, magOffset); 321 322 pmSourceOutputsMoments moments; 323 pmSourceOutputsSetMoments (&moments, source); 324 325 @PS1_DV?@ pmSourceDiffStats diffStats; 326 @PS1_DV?@ pmSourceDiffStatsInit(&diffStats); 327 @PS1_DV?@ if (source->diffStats) { diffStats = *source->diffStats;} 121 328 122 329 // the psMetadataAdd entry and the double quotes are used by grep to select the output fields for automatic documentation 123 330 // This set of psMetadataAdd Entries marks the "----" "Start of the PSF segment" 124 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET", PS_DATA_U32, "IPP detection identifier index", source->seq);125 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "X_PSF", PS_DATA_F32, "PSF x coordinate", outputs.xPos);126 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF", PS_DATA_F32, "PSF y coordinate", outputs.yPos);127 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG", PS_DATA_F32, "Sigma in PSF x coordinate", outputs.xErr);128 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG", PS_DATA_F32, "Sigma in PSF y coordinate", outputs.yErr);129 130 // NOTE: pre-PS1_V2, we only reported RA & DEC in floats for reference, not precision 131 @PS1_V1@ psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF", PS_DATA_F32, "PSF RA coordinate (degrees)", outputs.ra); 132 @PS1_V1@ psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF", PS_DATA_F32, "PSF DEC coordinate (degrees)", outputs.dec); 133 134 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE", PS_DATA_F32, "position angle at source (degrees)", outputs.posAngle);135 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE", PS_DATA_F32, "plate scale at source (arcsec/pixel)", outputs.pltScale);136 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG", PS_DATA_F32, "PSF fit instrumental magnitude", source->psfMag);137 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude", source->psfMagErr);138 139 @ALL,!PS1_V1,!PS1_V2@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX", PS_DATA_F32, "PSF fit instrumental flux (counts)", source->psfFlux); 140 @ALL,!PS1_V1,!PS1_V2@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental flux", source->psfFluxErr); 141 142 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG", PS_DATA_F32, "magnitude in standard aperture", source->apMag);143 @>PS1_V2,PS1_SV?,>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RAW", PS_DATA_F32, "magnitude in reported aperture", source->apMagRaw); 144 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS", PS_DATA_F32, "radius used for aperture mags", source->apRadius);145 @>PS1_DV1,>PS1_V3,>PS1_SV1@ psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX", PS_DATA_F32, "instrumental flux in standard aperture", source->apFlux); 146 @>PS1_DV1,>PS1_V3,>PS1_SV1@ psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX_SIG", PS_DATA_F32, "aperture flux error", source->apFluxErr); 147 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psMetadataAdd (row, PS_LIST_TAIL, "AP_NPIX", PS_DATA_S32, "aperture unmasked pixels", source->apNpixels); 148 149 @<PS1_V3,PS1_SV1,PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude", outputs.peakMag); 150 151 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG", PS_DATA_F32, "PSF Magnitude using supplied calibration", outputs.calMag);152 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG", PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr);153 154 // NOTE: RA & DEC (both double) need to be on an 8-byte boundary... 155 @ALL,!PS1_V1@ psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF", PS_DATA_F64, "PSF RA coordinate (degrees)", outputs.ra); 156 @ALL,!PS1_V1@ psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF", PS_DATA_F64, "PSF DEC coordinate (degrees)", outputs.dec); 157 158 @>=PS1_V3,>PS1_SV1@ psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude", outputs.peakMag); 159 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "SKY", PS_DATA_F32, "Sky level", source->sky);160 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA", PS_DATA_F32, "Sigma of sky level", source->skyErr);161 162 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ", PS_DATA_F32, "Chisq of PSF-fit", outputs.chisq);163 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA", PS_DATA_F32, "Nsigma deviations from PSF to CF", source->crNsigma);164 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA", PS_DATA_F32, "Nsigma deviations from PSF to EXT", source->extNsigma);331 @ALL@ psFitsTableSetU32 (table, i, "IPP_IDET", source->seq); // "IPP detection identifier index", 332 @ALL@ psFitsTableSetF32 (table, i, "X_PSF", outputs.xPos); // "PSF x coordinate", 333 @ALL@ psFitsTableSetF32 (table, i, "Y_PSF", outputs.yPos); // "PSF y coordinate", 334 @ALL@ psFitsTableSetF32 (table, i, "X_PSF_SIG", outputs.xErr); // "Sigma in PSF x coordinate", 335 @ALL@ psFitsTableSetF32 (table, i, "Y_PSF_SIG", outputs.yErr); // "Sigma in PSF y coordinate", 336 337 // NOTE: pre-PS1_V2, we only reported RA & DEC in floats for reference, not precision 338 @PS1_V1@ psFitsTableSetF32 (table, i, "RA_PSF", outputs.ra); // "PSF RA coordinate (degrees)", 339 @PS1_V1@ psFitsTableSetF32 (table, i, "DEC_PSF", outputs.dec); // "PSF DEC coordinate (degrees)", 340 341 @ALL@ psFitsTableSetF32 (table, i, "POSANGLE", outputs.posAngle); // "position angle at source (degrees)", 342 @ALL@ psFitsTableSetF32 (table, i, "PLTSCALE", outputs.pltScale); // "plate scale at source (arcsec/pixel)", 343 @ALL@ psFitsTableSetF32 (table, i, "PSF_INST_MAG", source->psfMag); // "PSF fit instrumental magnitude", 344 @ALL@ psFitsTableSetF32 (table, i, "PSF_INST_MAG_SIG", source->psfMagErr); // "Sigma of PSF instrumental magnitude", 345 346 @ALL,!PS1_V1,!PS1_V2@ psFitsTableSetF32 (table, i, "PSF_INST_FLUX", source->psfFlux); // "PSF fit instrumental flux (counts)", 347 @ALL,!PS1_V1,!PS1_V2@ psFitsTableSetF32 (table, i, "PSF_INST_FLUX_SIG", source->psfFluxErr); // "Sigma of PSF instrumental flux", 348 349 @ALL@ psFitsTableSetF32 (table, i, "AP_MAG", source->apMag); // "magnitude in standard aperture", 350 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableSetF32 (table, i, "AP_MAG_RAW", source->apMagRaw); // "magnitude in reported aperture", 351 @ALL@ psFitsTableSetF32 (table, i, "AP_MAG_RADIUS", source->apRadius); // "radius used for aperture mags", 352 @>PS1_DV1,>PS1_V3,>PS1_SV1@ psFitsTableSetF32 (table, i, "AP_FLUX", source->apFlux); // "instrumental flux in standard aperture", 353 @>PS1_DV1,>PS1_V3,>PS1_SV1@ psFitsTableSetF32 (table, i, "AP_FLUX_SIG", source->apFluxErr); // "aperture flux error", 354 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psFitsTableSetS32 (table, i, "AP_NPIX", source->apNpixels); // "aperture unmasked pixels", 355 356 @<PS1_V3,PS1_SV1,PS1_DV?@ psFitsTableSetF32 (table, i, "PEAK_FLUX_AS_MAG", outputs.peakMag); // "Peak flux expressed as magnitude" 357 358 @ALL@ psFitsTableSetF32 (table, i, "CAL_PSF_MAG", outputs.calMag); // "PSF Magnitude using supplied calibration", 359 @ALL@ psFitsTableSetF32 (table, i, "CAL_PSF_MAG_SIG", zeroptErr); // "measured scatter of zero point calibration", 360 361 // NOTE: RA & DEC (both double) need to be on an 8-byte boundary... 362 @ALL,!PS1_V1@ psFitsTableSetF64 (table, i, "RA_PSF", outputs.ra); // "PSF RA coordinate (degrees)", 363 @ALL,!PS1_V1@ psFitsTableSetF64 (table, i, "DEC_PSF", outputs.dec); // "PSF DEC coordinate (degrees)", 364 365 @>=PS1_V3,>PS1_SV1@ psFitsTableSetF32 (table, i, "PEAK_FLUX_AS_MAG", outputs.peakMag); // "Peak flux expressed as magnitude", 366 @ALL@ psFitsTableSetF32 (table, i, "SKY", source->sky); // "Sky level", 367 @ALL@ psFitsTableSetF32 (table, i, "SKY_SIGMA", source->skyErr); // "Sigma of sky level", 368 369 @ALL@ psFitsTableSetF32 (table, i, "PSF_CHISQ", outputs.chisq); // "Chisq of PSF-fit", 370 @ALL@ psFitsTableSetF32 (table, i, "CR_NSIGMA", source->crNsigma); // "Nsigma deviations from PSF to CF", 371 @ALL@ psFitsTableSetF32 (table, i, "EXT_NSIGMA", source->extNsigma); // "Nsigma deviations from PSF to EXT", 165 372 166 373 // PSF shape parameters: 167 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR", PS_DATA_F32, "PSF width (major axis)", outputs.psfMajor); 168 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR", PS_DATA_F32, "PSF width (minor axis)", outputs.psfMinor); 169 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA", PS_DATA_F32, "PSF orientation angle", outputs.psfTheta); 374 @ALL@ psFitsTableSetF32 (table, i, "PSF_MAJOR", outputs.psfMajor); // "PSF width (major axis)", 375 @ALL@ psFitsTableSetF32 (table, i, "PSF_MINOR", outputs.psfMinor); // "PSF width (minor axis)", 376 @ALL@ psFitsTableSetF32 (table, i, "PSF_THETA", outputs.psfTheta); // "PSF orientation angle", 377 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psFitsTableSetF32 (table, i, "PSF_CORE", outputs.psfCore); // "k term if defined", 378 379 // I use a look-up table and linear interpolation to map PSF_MAJOR,PSF_MINOR + PSF_CORE to FWHM values 380 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psFitsTableSetF32 (table, i, "PSF_FWHM_MAJ", outputs.psfMajorFWHM); // "PSF FWHM (major axis)", 381 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psFitsTableSetF32 (table, i, "PSF_FWHM_MIN", outputs.psfMinorFWHM); // "PSF FWHM (minor axis)", 382 383 // psf data quality 384 @ALL@ psFitsTableSetF32 (table, i, "PSF_QF", source->pixWeightNotBad); // "PSF coverage/quality factor (bad)", 385 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableSetF32 (table, i, "PSF_QF_PERFECT", source->pixWeightNotPoor); // "PSF coverage/quality factor (poor)", 386 @ALL@ psFitsTableSetS32 (table, i, "PSF_NDOF", outputs.nDOF); // "degrees of freedom", 387 @ALL@ psFitsTableSetS32 (table, i, "PSF_NPIX", outputs.nPix); // "number of pixels in fit", 388 389 @ALL@ psFitsTableSetF32 (table, i, "MOMENTS_XX", moments.Mxx); // "second moments (X^2)", 390 @ALL@ psFitsTableSetF32 (table, i, "MOMENTS_XY", moments.Mxy); // "second moments (X*Y)", 391 @ALL@ psFitsTableSetF32 (table, i, "MOMENTS_YY", moments.Myy); // "second moments (Y*Y)", 392 393 @>PS1_V2,PS1_SV?@ psFitsTableSetF32 (table, i, "MOMENTS_M3C", moments.M_c3); // "third momemt cos theta", 394 @>PS1_V2,PS1_SV?@ psFitsTableSetF32 (table, i, "MOMENTS_M3S", moments.M_s3); // "third momemt sin theta", 395 @>PS1_V2,PS1_SV?@ psFitsTableSetF32 (table, i, "MOMENTS_M4C", moments.M_c4); // "fourth momemt cos theta", 396 @>PS1_V2,PS1_SV?@ psFitsTableSetF32 (table, i, "MOMENTS_M4S", moments.M_s4); // "fourth momemt sin theta", 397 398 // Lensing parameters: 399 if (source->lensingOBJ && source->lensingOBJ->smear) { 400 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X11_SM_OBJ", source->lensingOBJ->smear->X11); // "smear polarizability element (objects)", 401 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X12_SM_OBJ", source->lensingOBJ->smear->X12); // "smear polarizability element (objects)", 402 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X22_SM_OBJ", source->lensingOBJ->smear->X22); // "smear polarizability element (objects)", 403 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E1_SM_OBJ", source->lensingOBJ->smear->e1); // "smear polarizability element (objects)", 404 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E2_SM_OBJ", source->lensingOBJ->smear->e2); // "smear polarizability element (objects)", 405 } 406 if (source->lensingOBJ && source->lensingOBJ->shear) { 407 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X11_SH_OBJ", source->lensingOBJ->shear->X11); // "shear polarizability element (objects)", 408 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X12_SH_OBJ", source->lensingOBJ->shear->X12); // "shear polarizability element (objects)", 409 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X22_SH_OBJ", source->lensingOBJ->shear->X22); // "shear polarizability element (objects)", 410 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E1_SH_OBJ", source->lensingOBJ->shear->e1); // "shear polarizability element (objects)", 411 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E2_SH_OBJ", source->lensingOBJ->shear->e2); // "shear polarizability element (objects)", 412 } 413 if (false && source->lensingOBJ) { 414 // do not bother to save these as they are equivalent to Mxx,Mxy,Myy above 415 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E1_PSF", source->lensingOBJ->e1); // "shear polarizability element (objects)", 416 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E2_PSF", source->lensingOBJ->e2); // "shear polarizability element (objects)", 417 } 418 419 if (source->lensingPSF && source->lensingPSF->smear) { 420 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X11_SM_PSF", source->lensingPSF->smear->X11); // "smear polarizability element (objects)", 421 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X12_SM_PSF", source->lensingPSF->smear->X12); // "smear polarizability element (objects)", 422 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X22_SM_PSF", source->lensingPSF->smear->X22); // "smear polarizability element (objects)", 423 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E1_SM_PSF", source->lensingPSF->smear->e1); // "smear polarizability element (objects)", 424 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E2_SM_PSF", source->lensingPSF->smear->e2); // "smear polarizability element (objects)", 425 } 426 if (source->lensingPSF && source->lensingPSF->shear) { 427 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X11_SH_PSF", source->lensingPSF->shear->X11); // "shear polarizability element (objects)", 428 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X12_SH_PSF", source->lensingPSF->shear->X12); // "shear polarizability element (objects)", 429 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_X22_SH_PSF", source->lensingPSF->shear->X22); // "shear polarizability element (objects)", 430 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E1_SH_PSF", source->lensingPSF->shear->e1); // "shear polarizability element (objects)", 431 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E2_SH_PSF", source->lensingPSF->shear->e2); // "shear polarizability element (objects)", 432 } 433 if (source->lensingPSF) { 434 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E1_PSF", source->lensingPSF->e1); // "shear polarizability element (objects)", 435 @>PS1_V4@ psFitsTableSetF32 (table, i, "LENS_E2_PSF", source->lensingPSF->e2); // "shear polarizability element (objects)", 436 } 437 438 // if lensing params exist also include the backmapped chipID and chip coordinates 439 if (source->lensingPSF && source->lensingPSF->shear) { 440 @>PS1_V4@ psFitsTableSetS16 (table, i, "SRC_CHIP_NUM", source->chipNum); // "id of warp input chip", 441 @>PS1_V4@ psFitsTableSetS16 (table, i, "SRC_CHIP_X", source->chipX); // "x coord in warp input chip", 442 @>PS1_V4@ psFitsTableSetS16 (table, i, "SRC_CHIP_Y", source->chipY); // "y coord in warp input chip", 443 @>PS1_V4@ psFitsTableSetS16 (table, i, "PADDING3", 0); // "more padding", 444 } 445 446 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableSetF32 (table, i, "MOMENTS_R1", moments.Mrf); // "first radial moment", 447 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableSetF32 (table, i, "MOMENTS_RH", moments.Mrh); // "half radial moment", 448 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableSetF32 (table, i, "KRON_FLUX", moments.Krf); // "Kron Flux (in 2.5 R1)", 449 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableSetF32 (table, i, "KRON_FLUX_ERR", moments.dKrf); // "Kron Flux Error", 450 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableSetF32 (table, i, "KRON_FLUX_INNER", moments.Kinner); // "Kron Flux (in 1.0 R1)", 451 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableSetF32 (table, i, "KRON_FLUX_OUTER", moments.Kouter); // "Kron Flux (in 4.0 R1)", 452 @>PS1_V3@ psFitsTableSetF32 (table, i, "SKY_LIMIT_RAD", source->skyRadius); // "Radius where object hits sky", 453 @>PS1_V3@ psFitsTableSetF32 (table, i, "SKY_LIMIT_FLUX", source->skyFlux); // "Flux / pix where object hits sky", 454 @>PS1_V3@ psFitsTableSetF32 (table, i, "SKY_LIMIT_SLOPE", source->skySlope); // "d(Flux/pix)/dRadius where object hits sky", 455 456 @>PS1_DV4@ psFitsTableSetS16 (table, i, "SRC_CHIP_NUM", source->chipNum); // "id of warp input chip", 457 @>PS1_DV4@ psFitsTableSetS16 (table, i, "SRC_CHIP_X", source->chipX); // "x coord in warp input chip", 458 @>PS1_DV4@ psFitsTableSetS16 (table, i, "SRC_CHIP_Y", source->chipY); // "y coord in warp input chip", 459 @>PS1_DV4@ psFitsTableSetS16 (table, i, "PADDING3", 0); // "more padding", 460 461 @PS1_DV?@ psFitsTableSetS32 (table, i, "DIFF_NPOS", diffStats.nGood); // "nPos (n pix > 3 sigma)", 462 @PS1_DV?@ psFitsTableSetF32 (table, i, "DIFF_FRATIO", diffStats.fRatio); // "fPos / (fPos + fNeg)", 463 @PS1_DV?@ psFitsTableSetF32 (table, i, "DIFF_NRATIO_BAD", diffStats.nRatioBad); // "nPos / (nPos + nNeg)", 464 @PS1_DV?@ psFitsTableSetF32 (table, i, "DIFF_NRATIO_MASK", diffStats.nRatioMask); // "nPos / (nPos + nMask)", 465 @PS1_DV?@ psFitsTableSetF32 (table, i, "DIFF_NRATIO_ALL", diffStats.nRatioAll); // "nPos / (nGood + nMask + nBad)", 466 467 @>PS1_DV1@ psFitsTableSetF32 (table, i, "DIFF_R_P", diffStats.Rp); // "distance to positive match source", 468 @>PS1_DV1@ psFitsTableSetF32 (table, i, "DIFF_SN_P", diffStats.SNp); // "signal-to-noise of pos match src", 469 @>PS1_DV1@ psFitsTableSetF32 (table, i, "DIFF_R_M", diffStats.Rm); // "distance to negative match source", 470 @>PS1_DV1@ psFitsTableSetF32 (table, i, "DIFF_SN_M", diffStats.SNm); // "signal-to-noise of neg match src", 471 472 @ALL@ psFitsTableSetU32 (table, i, "FLAGS", source->mode); // "psphot analysis flags", 473 @>PS1_V2,PS1_SV?,>PS1_DV1@ psFitsTableSetU32 (table, i, "FLAGS2", source->mode2); // "psphot analysis flags", 474 @PS1_V3,PS1_SV2@ psFitsTableSetS32 (table, i, "PADDING2", 0); // "padding", 475 476 @ALL@ psFitsTableSetU16 (table, i, "N_FRAMES", source->nFrames); // "Number of frames overlapping source center", 477 @ALL@ psFitsTableSetS16 (table, i, "PADDING", 0); // "padding", 478 } 479 480 // XXX why do we make a copy here to be supplemented with the masks? why not do this in the calling function? 481 psMetadata *header = psMetadataCopy(NULL, tableHeader); 482 pmSourceMasksHeader(header); 483 484 psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname); 485 if (!psFitsWriteTableNew(fits, header, table, extname)) { 486 psError(psErrorCodeLast(), false, "writing ext data %s\n", extname); 487 psFree(table); 488 psFree(header); 489 return false; 490 } 491 psFree(table); 492 psFree(header); 493 494 return true; 495 } 496 497 bool pmSourcesWrite_CMF_@CMFMODE@_Old (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe) 498 { 499 // fprintf (stderr, "writing with %s\n", __func__); 500 PS_ASSERT_PTR_NON_NULL(fits, false); 501 PS_ASSERT_PTR_NON_NULL(sources, false); 502 PS_ASSERT_PTR_NON_NULL(extname, false); 503 504 psArray *table; 505 psMetadata *row; 506 507 pmChip *chip = readout->parent->parent; 508 509 // if the sequence is defined, write these in seq order; otherwise 510 // write them in S/N order: 511 if (sources->n > 0) { 512 pmSource *source = (pmSource *) sources->data[0]; 513 if (source->seq == -1) { 514 // let's write these out in S/N order 515 sources = psArraySort (sources, pmSourceSortByFlux); 516 } else { 517 sources = psArraySort (sources, pmSourceSortBySeq); 518 } 519 } 520 521 table = psArrayAllocEmpty (sources->n); 522 523 float magOffset; 524 float zeroptErr; 525 float fwhmMajor; 526 float fwhmMinor; 527 pmSourceOutputsCommonValues (&magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader); 528 529 // we write out PSF-fits for all sources, regardless of quality. the source flags tell us the state 530 // by the time we call this function, all values should be assigned. let's use asserts to be sure in some cases. 531 for (int i = 0; i < sources->n; i++) { 532 // this is the source associated with this image 533 pmSource *thisSource = sources->data[i]; 534 535 // this is the "real" version of this source 536 pmSource *source = thisSource->parent ? thisSource->parent : thisSource; 537 538 // If source->seq is -1, source was generated in this analysis. If source->seq is 539 // not -1, source was read from elsewhere: in the latter case, preserve the source 540 // ID. source.seq is used instead of source.id since the latter is a const 541 // generated on Alloc, and would thus be wrong for read in sources. 542 if (source->seq == -1) { 543 source->seq = i; 544 } 545 546 // set the 'best' values for various output fields: 547 pmSourceOutputs outputs; 548 pmSourceOutputsSetValues (&outputs, source, chip, fwhmMajor, fwhmMinor, magOffset); 549 550 pmSourceOutputsMoments moments; 551 pmSourceOutputsSetMoments (&moments, source); 552 553 @PS1_DV?@ pmSourceDiffStats diffStats; 554 @PS1_DV?@ pmSourceDiffStatsInit(&diffStats); 555 @PS1_DV?@ if (source->diffStats) { 556 @PS1_DV?@ diffStats = *source->diffStats; 557 @PS1_DV?@ } 558 559 row = psMetadataAlloc (); 560 561 // the psMetadataAdd entry and the double quotes are used by grep to select the output fields for automatic documentation 562 // This set of psMetadataAdd Entries marks the "----" "Start of the PSF segment" 563 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET", PS_DATA_U32, "IPP detection identifier index", source->seq); 564 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "X_PSF", PS_DATA_F32, "PSF x coordinate", outputs.xPos); 565 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF", PS_DATA_F32, "PSF y coordinate", outputs.yPos); 566 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG", PS_DATA_F32, "Sigma in PSF x coordinate", outputs.xErr); 567 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG", PS_DATA_F32, "Sigma in PSF y coordinate", outputs.yErr); 568 569 // NOTE: pre-PS1_V2, we only reported RA & DEC in floats for reference, not precision 570 @PS1_V1@ psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF", PS_DATA_F32, "PSF RA coordinate (degrees)", outputs.ra); 571 @PS1_V1@ psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF", PS_DATA_F32, "PSF DEC coordinate (degrees)", outputs.dec); 572 573 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE", PS_DATA_F32, "position angle at source (degrees)", outputs.posAngle); 574 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE", PS_DATA_F32, "plate scale at source (arcsec/pixel)", outputs.pltScale); 575 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG", PS_DATA_F32, "PSF fit instrumental magnitude", source->psfMag); 576 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude", source->psfMagErr); 577 578 @ALL,!PS1_V1,!PS1_V2@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX", PS_DATA_F32, "PSF fit instrumental flux (counts)", source->psfFlux); 579 @ALL,!PS1_V1,!PS1_V2@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental flux", source->psfFluxErr); 580 581 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG", PS_DATA_F32, "magnitude in standard aperture", source->apMag); 582 @>PS1_V2,PS1_SV?,>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RAW", PS_DATA_F32, "magnitude in reported aperture", source->apMagRaw); 583 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS", PS_DATA_F32, "radius used for aperture mags", source->apRadius); 584 @>PS1_DV1,>PS1_V3,>PS1_SV1@ psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX", PS_DATA_F32, "instrumental flux in standard aperture", source->apFlux); 585 @>PS1_DV1,>PS1_V3,>PS1_SV1@ psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX_SIG", PS_DATA_F32, "aperture flux error", source->apFluxErr); 586 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psMetadataAdd (row, PS_LIST_TAIL, "AP_NPIX", PS_DATA_S32, "aperture unmasked pixels", source->apNpixels); 587 588 @<PS1_V3,PS1_SV1,PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude", outputs.peakMag); 589 590 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG", PS_DATA_F32, "PSF Magnitude using supplied calibration", outputs.calMag); 591 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG", PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr); 592 593 // NOTE: RA & DEC (both double) need to be on an 8-byte boundary... 594 @ALL,!PS1_V1@ psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF", PS_DATA_F64, "PSF RA coordinate (degrees)", outputs.ra); 595 @ALL,!PS1_V1@ psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF", PS_DATA_F64, "PSF DEC coordinate (degrees)", outputs.dec); 596 597 @>=PS1_V3,>PS1_SV1@ psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude", outputs.peakMag); 598 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "SKY", PS_DATA_F32, "Sky level", source->sky); 599 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA", PS_DATA_F32, "Sigma of sky level", source->skyErr); 600 601 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ", PS_DATA_F32, "Chisq of PSF-fit", outputs.chisq); 602 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA", PS_DATA_F32, "Nsigma deviations from PSF to CF", source->crNsigma); 603 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA", PS_DATA_F32, "Nsigma deviations from PSF to EXT", source->extNsigma); 604 605 // PSF shape parameters: 606 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR", PS_DATA_F32, "PSF width (major axis)", outputs.psfMajor); 607 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR", PS_DATA_F32, "PSF width (minor axis)", outputs.psfMinor); 608 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA", PS_DATA_F32, "PSF orientation angle", outputs.psfTheta); 170 609 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_CORE", PS_DATA_F32, "k term if defined", outputs.psfCore); 171 610 172 // I use a look-up table and linear interpolation to map PSF_MAJOR,PSF_MINOR + PSF_CORE to FWHM values611 // I use a look-up table and linear interpolation to map PSF_MAJOR,PSF_MINOR + PSF_CORE to FWHM values 173 612 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_FWHM_MAJ", PS_DATA_F32, "PSF FWHM (major axis)", outputs.psfMajorFWHM); 174 613 @>PS1_V4,>PS1_SV2,>PS1_DV3@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_FWHM_MIN", PS_DATA_F32, "PSF FWHM (minor axis)", outputs.psfMinorFWHM); 175 614 176 615 // psf data quality 177 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF", PS_DATA_F32, "PSF coverage/quality factor (bad)", source->pixWeightNotBad);178 @>PS1_V2,PS1_SV?,>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT", PS_DATA_F32, "PSF coverage/quality factor (poor)", source->pixWeightNotPoor);179 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF", PS_DATA_S32, "degrees of freedom", outputs.nDOF);180 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX", PS_DATA_S32, "number of pixels in fit", outputs.nPix);181 182 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX", PS_DATA_F32, "second moments (X^2)", moments.Mxx);183 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY", PS_DATA_F32, "second moments (X*Y)", moments.Mxy);184 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY", PS_DATA_F32, "second moments (Y*Y)", moments.Myy);185 186 @>PS1_V2,PS1_SV?@psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3C", PS_DATA_F32, "third momemt cos theta", moments.M_c3);187 @>PS1_V2,PS1_SV?@psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3S", PS_DATA_F32, "third momemt sin theta", moments.M_s3);188 @>PS1_V2,PS1_SV?@psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4C", PS_DATA_F32, "fourth momemt cos theta", moments.M_c4);189 @>PS1_V2,PS1_SV?@psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4S", PS_DATA_F32, "fourth momemt sin theta", moments.M_s4);190 191 // Lensing parameters:192 if (source->lensingOBJ && source->lensingOBJ->smear) {193 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X11_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->X11);194 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X12_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->X12);195 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X22_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->X22);196 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->e1);197 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->e2);198 }199 if (source->lensingOBJ && source->lensingOBJ->shear) {200 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X11_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->X11);201 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X12_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->X12);202 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X22_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->X22);203 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->e1);204 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->e2);205 }206 if (false && source->lensingOBJ) {207 // do not bother to save these as they are equivalent to Mxx,Mxy,Myy above208 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->e1);209 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->e2);210 }211 212 if (source->lensingPSF && source->lensingPSF->smear) {213 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X11_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->X11);214 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X12_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->X12);215 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X22_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->X22);216 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->e1);217 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->e2);218 }219 if (source->lensingPSF && source->lensingPSF->shear) {220 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X11_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->X11);221 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X12_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->X12);222 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X22_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->X22);223 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->e1);224 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->e2);225 }226 if (source->lensingPSF) {227 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->e1);228 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->e2);229 }616 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF", PS_DATA_F32, "PSF coverage/quality factor (bad)", source->pixWeightNotBad); 617 @>PS1_V2,PS1_SV?,>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT", PS_DATA_F32, "PSF coverage/quality factor (poor)", source->pixWeightNotPoor); 618 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF", PS_DATA_S32, "degrees of freedom", outputs.nDOF); 619 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX", PS_DATA_S32, "number of pixels in fit", outputs.nPix); 620 621 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX", PS_DATA_F32, "second moments (X^2)", moments.Mxx); 622 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY", PS_DATA_F32, "second moments (X*Y)", moments.Mxy); 623 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY", PS_DATA_F32, "second moments (Y*Y)", moments.Myy); 624 625 @>PS1_V2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3C", PS_DATA_F32, "third momemt cos theta", moments.M_c3); 626 @>PS1_V2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3S", PS_DATA_F32, "third momemt sin theta", moments.M_s3); 627 @>PS1_V2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4C", PS_DATA_F32, "fourth momemt cos theta", moments.M_c4); 628 @>PS1_V2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4S", PS_DATA_F32, "fourth momemt sin theta", moments.M_s4); 629 630 // Lensing parameters: 631 if (source->lensingOBJ && source->lensingOBJ->smear) { 632 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X11_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->X11); 633 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X12_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->X12); 634 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X22_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->X22); 635 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->e1); 636 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_SM_OBJ", PS_DATA_F32, "smear polarizability element (objects)", source->lensingOBJ->smear->e2); 637 } 638 if (source->lensingOBJ && source->lensingOBJ->shear) { 639 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X11_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->X11); 640 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X12_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->X12); 641 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X22_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->X22); 642 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->e1); 643 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_SH_OBJ", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->shear->e2); 644 } 645 if (false && source->lensingOBJ) { 646 // do not bother to save these as they are equivalent to Mxx,Mxy,Myy above 647 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->e1); 648 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingOBJ->e2); 649 } 650 651 if (source->lensingPSF && source->lensingPSF->smear) { 652 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X11_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->X11); 653 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X12_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->X12); 654 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X22_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->X22); 655 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->e1); 656 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_SM_PSF", PS_DATA_F32, "smear polarizability element (objects)", source->lensingPSF->smear->e2); 657 } 658 if (source->lensingPSF && source->lensingPSF->shear) { 659 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X11_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->X11); 660 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X12_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->X12); 661 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_X22_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->X22); 662 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->e1); 663 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_SH_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->shear->e2); 664 } 665 if (source->lensingPSF) { 666 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E1_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->e1); 667 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "LENS_E2_PSF", PS_DATA_F32, "shear polarizability element (objects)", source->lensingPSF->e2); 668 } 230 669 231 670 // if lensing params exist also include the backmapped chipID and chip coordinates 232 if (source->lensingPSF && source->lensingPSF->shear) {671 if (source->lensingPSF && source->lensingPSF->shear) { 233 672 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "SRC_CHIP_NUM", PS_DATA_S16, "id of warp input chip", source->chipNum); 234 673 @>PS1_V4@ psMetadataAdd (row, PS_LIST_TAIL, "SRC_CHIP_X", PS_DATA_S16, "x coord in warp input chip", source->chipX); … … 244 683 @>PS1_V2,PS1_SV?,>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER", PS_DATA_F32, "Kron Flux (in 4.0 R1)", moments.Kouter); 245 684 246 @>PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "SKY_LIMIT_RAD", PS_DATA_F32, "Radius where object hits sky", source->skyRadius);247 @>PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "SKY_LIMIT_FLUX", PS_DATA_F32, "Flux / pix where object hits sky", source->skyFlux);248 @>PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "SKY_LIMIT_SLOPE", PS_DATA_F32, "d(Flux/pix)/dRadius where object hits sky", source->skySlope);249 250 @>PS1_DV4@ psMetadataAdd (row, PS_LIST_TAIL, "SRC_CHIP_NUM", PS_DATA_S16, "id of warp input chip", source->chipNum);251 @>PS1_DV4@ psMetadataAdd (row, PS_LIST_TAIL, "SRC_CHIP_X", PS_DATA_S16, "x coord in warp input chip",source->chipX);252 @>PS1_DV4@ psMetadataAdd (row, PS_LIST_TAIL, "SRC_CHIP_Y", PS_DATA_S16, "y coord in warp input chip",source->chipY);253 @>PS1_DV4@ psMetadataAdd (row, PS_LIST_TAIL, "PADDING3", PS_DATA_S16, "more padding", 0);254 255 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NPOS", PS_DATA_S32, "nPos (n pix > 3 sigma)", diffStats.nGood);256 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_FRATIO", PS_DATA_F32, "fPos / (fPos + fNeg)", diffStats.fRatio);257 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_BAD", PS_DATA_F32, "nPos / (nPos + nNeg)", diffStats.nRatioBad);258 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_MASK", PS_DATA_F32, "nPos / (nPos + nMask)", diffStats.nRatioMask);259 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_ALL", PS_DATA_F32, "nPos / (nGood + nMask + nBad)", diffStats.nRatioAll);260 261 @>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_P", PS_DATA_F32, "distance to positive match source", diffStats.Rp);262 @>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_P", PS_DATA_F32, "signal-to-noise of pos match src", diffStats.SNp);263 @>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_M", PS_DATA_F32, "distance to negative match source", diffStats.Rm);264 @>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_M", PS_DATA_F32, "signal-to-noise of neg match src", diffStats.SNm);265 266 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "FLAGS", PS_DATA_U32, "psphot analysis flags", source->mode);267 @>PS1_V2,PS1_SV?,>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2", PS_DATA_U32, "psphot analysis flags", source->mode2);268 @PS1_V3,PS1_SV2@ psMetadataAdd (row, PS_LIST_TAIL, "PADDING2", PS_DATA_S32, "more padding", 0);269 @PS1_SV?@270 271 // note that this definition is inconsistent with the definition in272 // Ohana/src/libautocode/def. This version creates a table with data not273 // properly aligned with the 8-byte boundaries. The structure defined by274 // libautocode does this, but has a different order of elements (and adds275 // padding2 to fix things). We have generated may files with PS1_SV1 as is, so276 // I'll leave it. But in future a PS1_SV2 should be forced to match277 // libautocode. Note that addstar knows to detect the alternate version of278 // PS1_SV1 and correctly interpret its fields.279 280 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "N_FRAMES", PS_DATA_U16, "Number of frames overlapping source center", source->nFrames);281 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PADDING", PS_DATA_S16, "padding", 0);685 @>PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "SKY_LIMIT_RAD", PS_DATA_F32, "Radius where object hits sky", source->skyRadius); 686 @>PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "SKY_LIMIT_FLUX", PS_DATA_F32, "Flux / pix where object hits sky", source->skyFlux); 687 @>PS1_V3@ psMetadataAdd (row, PS_LIST_TAIL, "SKY_LIMIT_SLOPE", PS_DATA_F32, "d(Flux/pix)/dRadius where object hits sky", source->skySlope); 688 689 @>PS1_DV4@ psMetadataAdd (row, PS_LIST_TAIL, "SRC_CHIP_NUM", PS_DATA_S16, "id of warp input chip", source->chipNum); 690 @>PS1_DV4@ psMetadataAdd (row, PS_LIST_TAIL, "SRC_CHIP_X", PS_DATA_S16, "x coord in warp input chip", source->chipX); 691 @>PS1_DV4@ psMetadataAdd (row, PS_LIST_TAIL, "SRC_CHIP_Y", PS_DATA_S16, "y coord in warp input chip", source->chipY); 692 @>PS1_DV4@ psMetadataAdd (row, PS_LIST_TAIL, "PADDING3", PS_DATA_S16, "more padding", 0); 693 694 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NPOS", PS_DATA_S32, "nPos (n pix > 3 sigma)", diffStats.nGood); 695 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_FRATIO", PS_DATA_F32, "fPos / (fPos + fNeg)", diffStats.fRatio); 696 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_BAD", PS_DATA_F32, "nPos / (nPos + nNeg)", diffStats.nRatioBad); 697 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_MASK", PS_DATA_F32, "nPos / (nPos + nMask)", diffStats.nRatioMask); 698 @PS1_DV?@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_ALL", PS_DATA_F32, "nPos / (nGood + nMask + nBad)", diffStats.nRatioAll); 699 700 @>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_P", PS_DATA_F32, "distance to positive match source", diffStats.Rp); 701 @>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_P", PS_DATA_F32, "signal-to-noise of pos match src", diffStats.SNp); 702 @>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_M", PS_DATA_F32, "distance to negative match source", diffStats.Rm); 703 @>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_M", PS_DATA_F32, "signal-to-noise of neg match src", diffStats.SNm); 704 705 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "FLAGS", PS_DATA_U32, "psphot analysis flags", source->mode); 706 @>PS1_V2,PS1_SV?,>PS1_DV1@ psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2", PS_DATA_U32, "psphot analysis flags", source->mode2); 707 @PS1_V3,PS1_SV2@ psMetadataAdd (row, PS_LIST_TAIL, "PADDING2", PS_DATA_S32, "more padding", 0); 708 @PS1_SV?@ 709 710 // note that this definition is inconsistent with the definition in 711 // Ohana/src/libautocode/def. This version creates a table with data not 712 // properly aligned with the 8-byte boundaries. The structure defined by 713 // libautocode does this, but has a different order of elements (and adds 714 // padding2 to fix things). We have generated may files with PS1_SV1 as is, so 715 // I'll leave it. But in future a PS1_SV2 should be forced to match 716 // libautocode. Note that addstar knows to detect the alternate version of 717 // PS1_SV1 and correctly interpret its fields. 718 719 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "N_FRAMES", PS_DATA_U16, "Number of frames overlapping source center", source->nFrames); 720 @ALL@ psMetadataAdd (row, PS_LIST_TAIL, "PADDING", PS_DATA_S16, "padding", 0); 282 721 283 722 psArrayAdd (table, 100, row); … … 320 759 } 321 760 761 bool pmSourcesWrite_CMF_@CMFMODE@ (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe) 762 { 763 // bool status = pmSourcesWrite_CMF_@CMFMODE@_Old (fits, readout, sources, imageHeader, tableHeader, extname, recipe); 764 bool status = pmSourcesWrite_CMF_@CMFMODE@_New (fits, readout, sources, imageHeader, tableHeader, extname, recipe); 765 return status; 766 } 767 322 768 // read in a readout from the fits file 323 psArray *pmSourcesRead_CMF_@CMFMODE@ (psFits *fits, psMetadata *header)769 psArray *pmSourcesRead_CMF_@CMFMODE@_New (psFits *fits, psMetadata *header) 324 770 { 771 // fprintf (stderr, "reading with %s\n", __func__); 772 325 773 PS_ASSERT_PTR_NON_NULL(fits, false); 326 774 PS_ASSERT_PTR_NON_NULL(header, false); … … 355 803 psArray *sources = psArrayAlloc(numSources); // Array of sources, to return 356 804 357 // convert the table to the pmSource entriesa 805 // reads full table into memory 806 psFitsTable *table = psFitsReadTableNew (fits); 807 808 // convert the table to the pmSource entries 809 for (int i = 0; i < numSources; i++) { 810 pmSource *source = pmSourceAlloc (); 811 pmModel *model = pmModelAlloc (modelType); 812 source->modelPSF = model; 813 source->type = PM_SOURCE_TYPE_STAR; // XXX this should be added to the flags 814 815 // NOTE: A SEGV here because "model" is NULL is probably caused by not initialising the models. 816 PAR = model->params->data.F32; 817 dPAR = model->dparams->data.F32; 818 819 @ALL@ source->seq = psFitsTableGetU32 (&status, table, i, "IPP_IDET"); 820 @ALL@ PAR[PM_PAR_XPOS] = psFitsTableGetF32 (&status, table, i, "X_PSF"); 821 @ALL@ PAR[PM_PAR_YPOS] = psFitsTableGetF32 (&status, table, i, "Y_PSF"); 822 @ALL@ dPAR[PM_PAR_XPOS] = psFitsTableGetF32 (&status, table, i, "X_PSF_SIG"); 823 @ALL@ dPAR[PM_PAR_YPOS] = psFitsTableGetF32 (&status, table, i, "Y_PSF_SIG"); 824 @ALL@ axes.major = psFitsTableGetF32 (&status, table, i, "PSF_MAJOR"); 825 @ALL@ axes.minor = psFitsTableGetF32 (&status, table, i, "PSF_MINOR"); 826 @ALL@ axes.theta = psFitsTableGetF32 (&status, table, i, "PSF_THETA"); 827 @ALL@ axes.theta = axes.theta * PS_RAD_DEG; 828 829 @>PS1_V4,>PS1_SV2,>PS1_DV3@ if (model->params->n > PM_PAR_7) { 830 @>PS1_V4,>PS1_SV2,>PS1_DV3@ PAR[PM_PAR_7] = psFitsTableGetF32 (&status, table, i, "PSF_CORE"); 831 @>PS1_V4,>PS1_SV2,>PS1_DV3@ } 832 833 @ALL@ PAR[PM_PAR_SKY] = psFitsTableGetF32 (&status, table, i, "SKY"); 834 @ALL@ dPAR[PM_PAR_SKY] = psFitsTableGetF32 (&status, table, i, "SKY_SIGMA"); 835 @ALL@ source->sky = PAR[PM_PAR_SKY]; 836 @ALL@ source->skyErr = dPAR[PM_PAR_SKY]; 837 838 // XXX use these to determine PAR[PM_PAR_I0]? 839 @ALL@ source->psfMag = psFitsTableGetF32 (&status, table, i, "PSF_INST_MAG"); 840 @ALL@ source->psfMagErr = psFitsTableGetF32 (&status, table, i, "PSF_INST_MAG_SIG"); 841 @ALL@ source->apMag = psFitsTableGetF32 (&status, table, i, "AP_MAG"); 842 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->apMagRaw = psFitsTableGetF32 (&status, table, i, "AP_MAG_RAW"); 843 @>PS1_DV1,>PS1_V3,>PS1_SV1@ source->apFlux = psFitsTableGetF32 (&status, table, i, "AP_FLUX"); 844 @>PS1_DV1,>PS1_V3,>PS1_SV1@ source->apFluxErr = psFitsTableGetF32 (&status, table, i, "AP_FLUX_SIG"); 845 846 // XXX use these to determine PAR[PM_PAR_I0] if they exist? 847 // XXX add these to PS1_SV1? 848 @>PS1_V2,PS1_SV?,PS1_DV?@ source->psfFlux = psFitsTableGetF32 (&status, table, i, "PSF_INST_FLUX"); 849 @>PS1_V2,PS1_SV?,PS1_DV?@ source->psfFluxErr = psFitsTableGetF32 (&status, table, i, "PSF_INST_FLUX_SIG"); 850 851 // XXX this scaling is incorrect: does not include the 2 \pi AREA factor 852 @ALL@ PAR[PM_PAR_I0] = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN; 853 @ALL@ dPAR[PM_PAR_I0] = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN; 854 855 pmPSF_AxesToModel (PAR, axes, model->class->useReff); 856 857 @ALL@ float peakMag = psFitsTableGetF32 (&status, table, i, "PEAK_FLUX_AS_MAG"); 858 @ALL@ float peakFlux = (isfinite(peakMag)) ? pow(10.0, -0.4*peakMag) : NAN; 859 860 // recreate the peak to match (xPos, yPos) +/- (xErr, yErr) 861 @ALL@ source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE); 862 @ALL@ source->peak->rawFlux = peakFlux; 863 @ALL@ source->peak->smoothFlux = peakFlux; 864 @ALL@ source->peak->xf = PAR[PM_PAR_XPOS]; // more accurate position 865 @ALL@ source->peak->yf = PAR[PM_PAR_YPOS]; // more accurate position 866 @ALL@ source->peak->dx = dPAR[PM_PAR_XPOS]; 867 @ALL@ source->peak->dy = dPAR[PM_PAR_YPOS]; 868 869 @ALL@ source->pixWeightNotBad = psFitsTableGetF32 (&status, table, i, "PSF_QF"); 870 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->pixWeightNotPoor = psFitsTableGetF32 (&status, table, i, "PSF_QF_PERFECT"); 871 @ALL@ source->crNsigma = psFitsTableGetF32 (&status, table, i, "CR_NSIGMA"); 872 @ALL@ source->extNsigma = psFitsTableGetF32 (&status, table, i, "EXT_NSIGMA"); 873 @ALL@ source->apRadius = psFitsTableGetF32 (&status, table, i, "AP_MAG_RADIUS"); 874 @>PS1_V4,>PS1_SV2,>PS1_DV3@ source->apNpixels = psFitsTableGetS32 (&status, table, i, "AP_NPIX"); 875 876 // note that some older versions used PSF_PROBABILITY: this was not well defined. 877 @ALL@ model->chisq = psFitsTableGetF32 (&status, table, i, "PSF_CHISQ"); 878 @ALL@ model->nDOF = psFitsTableGetS32 (&status, table, i, "PSF_NDOF"); 879 @ALL@ model->nPix = psFitsTableGetS32 (&status, table, i, "PSF_NPIX"); 880 881 @ALL@ source->moments = pmMomentsAlloc (); 882 @ALL@ source->moments->Mx = source->peak->xf; // we don't have both Mx,My and xf,yf in the cmf 883 @ALL@ source->moments->My = source->peak->yf; // we don't have both Mx,My and xf,yf in the cmf 884 885 @ALL@ source->moments->Mxx = psFitsTableGetF32 (&status, table, i, "MOMENTS_XX"); 886 @ALL@ source->moments->Mxy = psFitsTableGetF32 (&status, table, i, "MOMENTS_XY"); 887 @ALL@ source->moments->Myy = psFitsTableGetF32 (&status, table, i, "MOMENTS_YY"); 888 889 // XXX we do not save all of the 3rd and 4th moment parameters. when we load in data, 890 // we are storing enough information so the output will be consistent with the input 891 @>PS1_V2,PS1_SV?@ source->moments->Mxxx = +1.00 * psFitsTableGetF32 (&status, table, i, "MOMENTS_M3C"); 892 @>PS1_V2,PS1_SV?@ source->moments->Mxxy = 0.00; 893 @>PS1_V2,PS1_SV?@ source->moments->Mxyy = 0.00; 894 @>PS1_V2,PS1_SV?@ source->moments->Myyy = -1.00 * psFitsTableGetF32 (&status, table, i, "MOMENTS_M3S"); 895 @>PS1_V2,PS1_SV?@ source->moments->Mxxxx = +1.00 * psFitsTableGetF32 (&status, table, i, "MOMENTS_M4C"); 896 @>PS1_V2,PS1_SV?@ source->moments->Mxxxy = 0.00; 897 @>PS1_V2,PS1_SV?@ source->moments->Mxxyy = 0.00; 898 @>PS1_V2,PS1_SV?@ source->moments->Mxyyy = -0.25 * psFitsTableGetF32 (&status, table, i, "MOMENTS_M4S"); 899 @>PS1_V2,PS1_SV?@ source->moments->Myyyy = 0.00; 900 901 // Lensing parameters (on read if PS1_V5+) 902 if (haveLensOBJ) { 903 source->lensingOBJ = pmSourceLensingAlloc (); 904 source->lensingOBJ->smear = pmLensingParsAlloc(); 905 source->lensingOBJ->shear = pmLensingParsAlloc(); 906 907 @>PS1_V4@ source->lensingOBJ->smear->X11 = psFitsTableGetF32 (&status, table, i, "LENS_X11_SM_OBJ"); 908 @>PS1_V4@ source->lensingOBJ->smear->X12 = psFitsTableGetF32 (&status, table, i, "LENS_X12_SM_OBJ"); 909 @>PS1_V4@ source->lensingOBJ->smear->X22 = psFitsTableGetF32 (&status, table, i, "LENS_X22_SM_OBJ"); 910 @>PS1_V4@ source->lensingOBJ->smear->e1 = psFitsTableGetF32 (&status, table, i, "LENS_E1_SM_OBJ"); 911 @>PS1_V4@ source->lensingOBJ->smear->e2 = psFitsTableGetF32 (&status, table, i, "LENS_E2_SM_OBJ"); 912 @>PS1_V4@ source->lensingOBJ->shear->X11 = psFitsTableGetF32 (&status, table, i, "LENS_X11_SH_OBJ"); 913 @>PS1_V4@ source->lensingOBJ->shear->X12 = psFitsTableGetF32 (&status, table, i, "LENS_X12_SH_OBJ"); 914 @>PS1_V4@ source->lensingOBJ->shear->X22 = psFitsTableGetF32 (&status, table, i, "LENS_X22_SH_OBJ"); 915 @>PS1_V4@ source->lensingOBJ->shear->e1 = psFitsTableGetF32 (&status, table, i, "LENS_E1_SH_OBJ"); 916 @>PS1_V4@ source->lensingOBJ->shear->e2 = psFitsTableGetF32 (&status, table, i, "LENS_E2_SH_OBJ"); 917 } 918 919 @>PS1_V4@ source->chipNum = psFitsTableGetS16 (&status, table, i, "SRC_CHIP_NUM"); 920 @>PS1_V4@ source->chipX = psFitsTableGetS16 (&status, table, i, "SRC_CHIP_X"); 921 @>PS1_V4@ source->chipY = psFitsTableGetS16 (&status, table, i, "SRC_CHIP_Y"); 922 923 if (haveLensPSF) { 924 source->lensingPSF = pmSourceLensingAlloc (); 925 source->lensingPSF->smear = pmLensingParsAlloc(); 926 source->lensingPSF->shear = pmLensingParsAlloc(); 927 928 @>PS1_V4@ source->lensingPSF->smear->X11 = psFitsTableGetF32 (&status, table, i, "LENS_X11_SM_PSF"); 929 @>PS1_V4@ source->lensingPSF->smear->X12 = psFitsTableGetF32 (&status, table, i, "LENS_X12_SM_PSF"); 930 @>PS1_V4@ source->lensingPSF->smear->X22 = psFitsTableGetF32 (&status, table, i, "LENS_X22_SM_PSF"); 931 @>PS1_V4@ source->lensingPSF->smear->e1 = psFitsTableGetF32 (&status, table, i, "LENS_E1_SM_PSF"); 932 @>PS1_V4@ source->lensingPSF->smear->e2 = psFitsTableGetF32 (&status, table, i, "LENS_E2_SM_PSF"); 933 @>PS1_V4@ source->lensingPSF->shear->X11 = psFitsTableGetF32 (&status, table, i, "LENS_X11_SH_PSF"); 934 @>PS1_V4@ source->lensingPSF->shear->X12 = psFitsTableGetF32 (&status, table, i, "LENS_X12_SH_PSF"); 935 @>PS1_V4@ source->lensingPSF->shear->X22 = psFitsTableGetF32 (&status, table, i, "LENS_X22_SH_PSF"); 936 @>PS1_V4@ source->lensingPSF->shear->e1 = psFitsTableGetF32 (&status, table, i, "LENS_E1_SH_PSF"); 937 @>PS1_V4@ source->lensingPSF->shear->e2 = psFitsTableGetF32 (&status, table, i, "LENS_E2_SH_PSF"); 938 @>PS1_V4@ source->lensingPSF->e1 = psFitsTableGetF32 (&status, table, i, "LENS_E1_PSF"); 939 @>PS1_V4@ source->lensingPSF->e2 = psFitsTableGetF32 (&status, table, i, "LENS_E2_PSF"); 940 } 941 942 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->moments->Mrf = psFitsTableGetF32 (&status, table, i, "MOMENTS_R1"); 943 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->moments->Mrh = psFitsTableGetF32 (&status, table, i, "MOMENTS_RH"); 944 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->moments->KronFlux = psFitsTableGetF32 (&status, table, i, "KRON_FLUX"); 945 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->moments->KronFluxErr = psFitsTableGetF32 (&status, table, i, "KRON_FLUX_ERR"); 946 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->moments->KronFinner = psFitsTableGetF32 (&status, table, i, "KRON_FLUX_INNER"); 947 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->moments->KronFouter = psFitsTableGetF32 (&status, table, i, "KRON_FLUX_OUTER"); 948 949 @>PS1_V3@ source->skyRadius = psFitsTableGetF32 (&status, table, i, "SKY_LIMIT_RAD"); 950 @>PS1_V3@ source->skyFlux = psFitsTableGetF32 (&status, table, i, "SKY_LIMIT_FLUX"); 951 @>PS1_V3@ source->skySlope = psFitsTableGetF32 (&status, table, i, "SKY_LIMIT_SLOPE"); 952 953 @PS1_DV?@ int nPos = psFitsTableGetS32 (&status, table, i, "DIFF_NPOS"); 954 @PS1_DV?@ if (nPos) { 955 @PS1_DV?@ source->diffStats = pmSourceDiffStatsAlloc(); 956 @PS1_DV?@ source->diffStats->nGood = nPos; 957 @PS1_DV?@ source->diffStats->fRatio = psFitsTableGetF32 (&status, table, i, "DIFF_FRATIO"); 958 @PS1_DV?@ source->diffStats->nRatioBad = psFitsTableGetF32 (&status, table, i, "DIFF_NRATIO_BAD"); 959 @PS1_DV?@ source->diffStats->nRatioMask = psFitsTableGetF32 (&status, table, i, "DIFF_NRATIO_MASK"); 960 @PS1_DV?@ source->diffStats->nRatioAll = psFitsTableGetF32 (&status, table, i, "DIFF_NRATIO_ALL"); 961 962 @>PS1_DV1@ source->diffStats->Rp = psFitsTableGetF32 (&status, table, i, "DIFF_R_P"); 963 @>PS1_DV1@ source->diffStats->SNp = psFitsTableGetF32 (&status, table, i, "DIFF_SN_P"); 964 @>PS1_DV1@ source->diffStats->Rm = psFitsTableGetF32 (&status, table, i, "DIFF_R_M"); 965 @>PS1_DV1@ source->diffStats->SNm = psFitsTableGetF32 (&status, table, i, "DIFF_SN_M"); 966 @PS1_DV?@ } 967 968 @ALL@ source->mode = psFitsTableGetU32 (&status, table, i, "FLAGS"); 969 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->mode2 = psFitsTableGetU32 (&status, table, i, "FLAGS2"); 970 @ALL@ source->nFrames = psFitsTableGetU16 (&status, table, i, "N_FRAMES"); 971 assert (status); 972 973 sources->data[i] = source; 974 } 975 psFree (table); 976 return sources; 977 } 978 979 // read in a readout from the fits file 980 psArray *pmSourcesRead_CMF_@CMFMODE@_Old (psFits *fits, psMetadata *header) 981 { 982 // fprintf (stderr, "reading with %s\n", __func__); 983 984 PS_ASSERT_PTR_NON_NULL(fits, false); 985 PS_ASSERT_PTR_NON_NULL(header, false); 986 987 bool status; 988 psF32 *PAR, *dPAR; 989 psEllipseAxes axes; 990 991 // define PSF model type 992 int defaultModelType = pmModelClassGetType ("PS_MODEL_GAUSS"); 993 int modelType = -1; 994 995 // if header does not define the model, default to a gaussian 996 char *PSF_NAME = psMetadataLookupStr (&status, header, "PSFMODEL"); 997 if (PSF_NAME != NULL) { 998 modelType = pmModelClassGetType (PSF_NAME); 999 } 1000 // work around bug in psphotFullForce 1001 if (modelType < 0) { 1002 modelType = defaultModelType; 1003 } 1004 // assert (modelType > -1); 1005 1006 // do we expect to find lensing parameters? 1007 bool haveLensOBJ = psMetadataLookupBool (&status, header, "LENS_OBJ"); 1008 bool haveLensPSF = psMetadataLookupBool (&status, header, "LENS_PSF"); 1009 1010 // We get the size of the table, and allocate the array of sources first because the table 1011 // is large and ephemeral --- when the table gets blown away, whatever is allocated after 1012 // the table is read blocks the free. In fact, it's better to read the table row by row. 1013 long numSources = psFitsTableSize(fits); // Number of sources in table 1014 psArray *sources = psArrayAlloc(numSources); // Array of sources, to return 1015 1016 // convert the table to the pmSource entries 358 1017 for (int i = 0; i < numSources; i++) { 359 1018 psMetadata *row = psFitsReadTableRow(fits, i); // Table row … … 382 1041 @ALL@ axes.theta = psMetadataLookupF32 (&status, row, "PSF_THETA"); 383 1042 @ALL@ axes.theta = axes.theta * PS_RAD_DEG; 384 385 @>PS1_V4,>PS1_SV2,>PS1_DV3@ if (model->params->n > PM_PAR_7) {386 @>PS1_V4,>PS1_SV2,>PS1_DV3@ PAR[PM_PAR_7] = psMetadataLookupF32 (&status, row, "PSF_CORE");387 @>PS1_V4,>PS1_SV2,>PS1_DV3@ }1043 1044 @>PS1_V4,>PS1_SV2,>PS1_DV3@ if (model->params->n > PM_PAR_7) { 1045 @>PS1_V4,>PS1_SV2,>PS1_DV3@ PAR[PM_PAR_7] = psMetadataLookupF32 (&status, row, "PSF_CORE"); 1046 @>PS1_V4,>PS1_SV2,>PS1_DV3@ } 388 1047 389 1048 @ALL@ PAR[PM_PAR_SKY] = psMetadataLookupF32 (&status, row, "SKY"); … … 396 1055 @ALL@ source->psfMagErr = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG"); 397 1056 @ALL@ source->apMag = psMetadataLookupF32 (&status, row, "AP_MAG"); 398 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->apMagRaw = psMetadataLookupF32 (&status, row, "AP_MAG_RAW");399 @>PS1_DV1,>PS1_V3,>PS1_SV1@ source->apFlux= psMetadataLookupF32 (&status, row, "AP_FLUX");400 @>PS1_DV1,>PS1_V3,>PS1_SV1@ source->apFluxErr = psMetadataLookupF32 (&status, row, "AP_FLUX_SIG");1057 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->apMagRaw = psMetadataLookupF32 (&status, row, "AP_MAG_RAW"); 1058 @>PS1_DV1,>PS1_V3,>PS1_SV1@ source->apFlux = psMetadataLookupF32 (&status, row, "AP_FLUX"); 1059 @>PS1_DV1,>PS1_V3,>PS1_SV1@ source->apFluxErr = psMetadataLookupF32 (&status, row, "AP_FLUX_SIG"); 401 1060 402 1061 // XXX use these to determine PAR[PM_PAR_I0] if they exist? 403 // XXX add these to PS1_SV1?404 @>PS1_V2,PS1_SV?,PS1_DV?@ source->psfFlux = psMetadataLookupF32 (&status, row, "PSF_INST_FLUX");405 @>PS1_V2,PS1_SV?,PS1_DV?@ source->psfFluxErr= psMetadataLookupF32 (&status, row, "PSF_INST_FLUX_SIG");1062 // XXX add these to PS1_SV1? 1063 @>PS1_V2,PS1_SV?,PS1_DV?@ source->psfFlux = psMetadataLookupF32 (&status, row, "PSF_INST_FLUX"); 1064 @>PS1_V2,PS1_SV?,PS1_DV?@ source->psfFluxErr= psMetadataLookupF32 (&status, row, "PSF_INST_FLUX_SIG"); 406 1065 407 1066 // XXX this scaling is incorrect: does not include the 2 \pi AREA factor … … 424 1083 425 1084 @ALL@ source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF"); 426 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->pixWeightNotPoor = psMetadataLookupF32 (&status, row, "PSF_QF_PERFECT");1085 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->pixWeightNotPoor = psMetadataLookupF32 (&status, row, "PSF_QF_PERFECT"); 427 1086 @ALL@ source->crNsigma = psMetadataLookupF32 (&status, row, "CR_NSIGMA"); 428 1087 @ALL@ source->extNsigma = psMetadataLookupF32 (&status, row, "EXT_NSIGMA"); 429 1088 @ALL@ source->apRadius = psMetadataLookupF32 (&status, row, "AP_MAG_RADIUS"); 430 @>PS1_V4,>PS1_SV2,>PS1_DV3@ source->apNpixels = psMetadataLookupS32 (&status, row, "AP_NPIX");1089 @>PS1_V4,>PS1_SV2,>PS1_DV3@ source->apNpixels = psMetadataLookupS32 (&status, row, "AP_NPIX"); 431 1090 432 1091 // note that some older versions used PSF_PROBABILITY: this was not well defined. … … 443 1102 @ALL@ source->moments->Myy = psMetadataLookupF32 (&status, row, "MOMENTS_YY"); 444 1103 445 // XXX we do not save all of the 3rd and 4th moment parameters. when we load in data,446 // we are storing enough information so the output will be consistent with the input1104 // XXX we do not save all of the 3rd and 4th moment parameters. when we load in data, 1105 // we are storing enough information so the output will be consistent with the input 447 1106 @>PS1_V2,PS1_SV?@ source->moments->Mxxx = +1.0 * psMetadataLookupF32 (&status, row, "MOMENTS_M3C"); 448 1107 @>PS1_V2,PS1_SV?@ source->moments->Mxxy = 0.0; … … 456 1115 @>PS1_V2,PS1_SV?@ source->moments->Myyyy = 0.0; 457 1116 458 // Lensing parameters (on read if PS1_V5+)459 if (haveLensOBJ) {460 source->lensingOBJ = pmSourceLensingAlloc ();461 source->lensingOBJ->smear = pmLensingParsAlloc();462 source->lensingOBJ->shear = pmLensingParsAlloc();463 464 @>PS1_V4@ source->lensingOBJ->smear->X11 = psMetadataLookupF32 (&status, row, "LENS_X11_SM_OBJ");465 @>PS1_V4@ source->lensingOBJ->smear->X12 = psMetadataLookupF32 (&status, row, "LENS_X12_SM_OBJ");466 @>PS1_V4@ source->lensingOBJ->smear->X22 = psMetadataLookupF32 (&status, row, "LENS_X22_SM_OBJ");467 @>PS1_V4@ source->lensingOBJ->smear->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_SM_OBJ");468 @>PS1_V4@ source->lensingOBJ->smear->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_SM_OBJ");469 @>PS1_V4@ source->lensingOBJ->shear->X11 = psMetadataLookupF32 (&status, row, "LENS_X11_SH_OBJ");470 @>PS1_V4@ source->lensingOBJ->shear->X12 = psMetadataLookupF32 (&status, row, "LENS_X12_SH_OBJ");471 @>PS1_V4@ source->lensingOBJ->shear->X22 = psMetadataLookupF32 (&status, row, "LENS_X22_SH_OBJ");472 @>PS1_V4@ source->lensingOBJ->shear->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_SH_OBJ");473 @>PS1_V4@ source->lensingOBJ->shear->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_SH_OBJ");474 }475 476 @>PS1_V4@ source->chipNum = psMetadataLookupS16 (&status, row, "SRC_CHIP_NUM");477 @>PS1_V4@ source->chipX = psMetadataLookupS16 (&status, row, "SRC_CHIP_X");478 @>PS1_V4@ source->chipY = psMetadataLookupS16 (&status, row, "SRC_CHIP_Y");479 480 if (haveLensPSF) {481 source->lensingPSF = pmSourceLensingAlloc ();482 source->lensingPSF->smear = pmLensingParsAlloc();483 source->lensingPSF->shear = pmLensingParsAlloc();484 485 @>PS1_V4@ source->lensingPSF->smear->X11 = psMetadataLookupF32 (&status, row, "LENS_X11_SM_PSF");486 @>PS1_V4@ source->lensingPSF->smear->X12 = psMetadataLookupF32 (&status, row, "LENS_X12_SM_PSF");487 @>PS1_V4@ source->lensingPSF->smear->X22 = psMetadataLookupF32 (&status, row, "LENS_X22_SM_PSF");488 @>PS1_V4@ source->lensingPSF->smear->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_SM_PSF");489 @>PS1_V4@ source->lensingPSF->smear->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_SM_PSF");490 @>PS1_V4@ source->lensingPSF->shear->X11 = psMetadataLookupF32 (&status, row, "LENS_X11_SH_PSF");491 @>PS1_V4@ source->lensingPSF->shear->X12 = psMetadataLookupF32 (&status, row, "LENS_X12_SH_PSF");492 @>PS1_V4@ source->lensingPSF->shear->X22 = psMetadataLookupF32 (&status, row, "LENS_X22_SH_PSF");493 @>PS1_V4@ source->lensingPSF->shear->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_SH_PSF");494 @>PS1_V4@ source->lensingPSF->shear->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_SH_PSF");495 @>PS1_V4@ source->lensingPSF->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_PSF");496 @>PS1_V4@ source->lensingPSF->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_PSF");497 }1117 // Lensing parameters (on read if PS1_V5+) 1118 if (haveLensOBJ) { 1119 source->lensingOBJ = pmSourceLensingAlloc (); 1120 source->lensingOBJ->smear = pmLensingParsAlloc(); 1121 source->lensingOBJ->shear = pmLensingParsAlloc(); 1122 1123 @>PS1_V4@ source->lensingOBJ->smear->X11 = psMetadataLookupF32 (&status, row, "LENS_X11_SM_OBJ"); 1124 @>PS1_V4@ source->lensingOBJ->smear->X12 = psMetadataLookupF32 (&status, row, "LENS_X12_SM_OBJ"); 1125 @>PS1_V4@ source->lensingOBJ->smear->X22 = psMetadataLookupF32 (&status, row, "LENS_X22_SM_OBJ"); 1126 @>PS1_V4@ source->lensingOBJ->smear->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_SM_OBJ"); 1127 @>PS1_V4@ source->lensingOBJ->smear->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_SM_OBJ"); 1128 @>PS1_V4@ source->lensingOBJ->shear->X11 = psMetadataLookupF32 (&status, row, "LENS_X11_SH_OBJ"); 1129 @>PS1_V4@ source->lensingOBJ->shear->X12 = psMetadataLookupF32 (&status, row, "LENS_X12_SH_OBJ"); 1130 @>PS1_V4@ source->lensingOBJ->shear->X22 = psMetadataLookupF32 (&status, row, "LENS_X22_SH_OBJ"); 1131 @>PS1_V4@ source->lensingOBJ->shear->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_SH_OBJ"); 1132 @>PS1_V4@ source->lensingOBJ->shear->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_SH_OBJ"); 1133 } 1134 1135 @>PS1_V4@ source->chipNum = psMetadataLookupS16 (&status, row, "SRC_CHIP_NUM"); 1136 @>PS1_V4@ source->chipX = psMetadataLookupS16 (&status, row, "SRC_CHIP_X"); 1137 @>PS1_V4@ source->chipY = psMetadataLookupS16 (&status, row, "SRC_CHIP_Y"); 1138 1139 if (haveLensPSF) { 1140 source->lensingPSF = pmSourceLensingAlloc (); 1141 source->lensingPSF->smear = pmLensingParsAlloc(); 1142 source->lensingPSF->shear = pmLensingParsAlloc(); 1143 1144 @>PS1_V4@ source->lensingPSF->smear->X11 = psMetadataLookupF32 (&status, row, "LENS_X11_SM_PSF"); 1145 @>PS1_V4@ source->lensingPSF->smear->X12 = psMetadataLookupF32 (&status, row, "LENS_X12_SM_PSF"); 1146 @>PS1_V4@ source->lensingPSF->smear->X22 = psMetadataLookupF32 (&status, row, "LENS_X22_SM_PSF"); 1147 @>PS1_V4@ source->lensingPSF->smear->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_SM_PSF"); 1148 @>PS1_V4@ source->lensingPSF->smear->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_SM_PSF"); 1149 @>PS1_V4@ source->lensingPSF->shear->X11 = psMetadataLookupF32 (&status, row, "LENS_X11_SH_PSF"); 1150 @>PS1_V4@ source->lensingPSF->shear->X12 = psMetadataLookupF32 (&status, row, "LENS_X12_SH_PSF"); 1151 @>PS1_V4@ source->lensingPSF->shear->X22 = psMetadataLookupF32 (&status, row, "LENS_X22_SH_PSF"); 1152 @>PS1_V4@ source->lensingPSF->shear->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_SH_PSF"); 1153 @>PS1_V4@ source->lensingPSF->shear->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_SH_PSF"); 1154 @>PS1_V4@ source->lensingPSF->e1 = psMetadataLookupF32 (&status, row, "LENS_E1_PSF"); 1155 @>PS1_V4@ source->lensingPSF->e2 = psMetadataLookupF32 (&status, row, "LENS_E2_PSF"); 1156 } 498 1157 499 1158 @>PS1_V2,PS1_SV?,>PS1_DV1@ source->moments->Mrf = psMetadataLookupF32 (&status, row, "MOMENTS_R1"); … … 508 1167 @>PS1_V3@ source->skySlope = psMetadataLookupF32 (&status, row, "SKY_LIMIT_SLOPE"); 509 1168 510 @PS1_DV?@ int nPos = psMetadataLookupS32 (&status, row, "DIFF_NPOS");511 @PS1_DV?@ if (nPos) {512 @PS1_DV?@ source->diffStats = pmSourceDiffStatsAlloc();513 @PS1_DV?@ source->diffStats->nGood = nPos;514 @PS1_DV?@ source->diffStats->fRatio = psMetadataLookupF32 (&status, row, "DIFF_FRATIO");515 @PS1_DV?@ source->diffStats->nRatioBad = psMetadataLookupF32 (&status, row, "DIFF_NRATIO_BAD");516 @PS1_DV?@ source->diffStats->nRatioMask = psMetadataLookupF32 (&status, row, "DIFF_NRATIO_MASK");517 @PS1_DV?@ source->diffStats->nRatioAll = psMetadataLookupF32 (&status, row, "DIFF_NRATIO_ALL");518 519 @>PS1_DV1@ source->diffStats->Rp = psMetadataLookupF32 (&status, row, "DIFF_R_P");520 @>PS1_DV1@ source->diffStats->SNp = psMetadataLookupF32 (&status, row, "DIFF_SN_P");521 @>PS1_DV1@ source->diffStats->Rm = psMetadataLookupF32 (&status, row, "DIFF_R_M");522 @>PS1_DV1@ source->diffStats->SNm = psMetadataLookupF32 (&status, row, "DIFF_SN_M");523 @PS1_DV?@ }1169 @PS1_DV?@ int nPos = psMetadataLookupS32 (&status, row, "DIFF_NPOS"); 1170 @PS1_DV?@ if (nPos) { 1171 @PS1_DV?@ source->diffStats = pmSourceDiffStatsAlloc(); 1172 @PS1_DV?@ source->diffStats->nGood = nPos; 1173 @PS1_DV?@ source->diffStats->fRatio = psMetadataLookupF32 (&status, row, "DIFF_FRATIO"); 1174 @PS1_DV?@ source->diffStats->nRatioBad = psMetadataLookupF32 (&status, row, "DIFF_NRATIO_BAD"); 1175 @PS1_DV?@ source->diffStats->nRatioMask = psMetadataLookupF32 (&status, row, "DIFF_NRATIO_MASK"); 1176 @PS1_DV?@ source->diffStats->nRatioAll = psMetadataLookupF32 (&status, row, "DIFF_NRATIO_ALL"); 1177 1178 @>PS1_DV1@ source->diffStats->Rp = psMetadataLookupF32 (&status, row, "DIFF_R_P"); 1179 @>PS1_DV1@ source->diffStats->SNp = psMetadataLookupF32 (&status, row, "DIFF_SN_P"); 1180 @>PS1_DV1@ source->diffStats->Rm = psMetadataLookupF32 (&status, row, "DIFF_R_M"); 1181 @>PS1_DV1@ source->diffStats->SNm = psMetadataLookupF32 (&status, row, "DIFF_SN_M"); 1182 @PS1_DV?@ } 524 1183 525 1184 @ALL@ source->mode = psMetadataLookupU32 (&status, row, "FLAGS"); … … 533 1192 534 1193 return sources; 1194 } 1195 1196 psArray *pmSourcesRead_CMF_@CMFMODE@ (psFits *fits, psMetadata *header) { 1197 // psArray *array = pmSourcesRead_CMF_@CMFMODE@_Old (fits, header); 1198 psArray *array = pmSourcesRead_CMF_@CMFMODE@_New (fits, header); 1199 return array; 535 1200 } 536 1201 … … 599 1264 // write the radial profile apertures to header 600 1265 for (int i = 0; i < radMax->n; i++) { 601 sprintf (keyword1, "RMIN_%02d", i);602 sprintf (keyword2, "RMAX_%02d", i);603 psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]);604 psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "max radius for SB profile", radMax->data.F32[i]);1266 sprintf (keyword1, "RMIN_%02d", i); 1267 sprintf (keyword2, "RMAX_%02d", i); 1268 psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]); 1269 psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "max radius for SB profile", radMax->data.F32[i]); 605 1270 } 606 1271 607 1272 // we write out all sources, regardless of quality. the source flags tell us the state 608 1273 for (int i = 0; i < sources->n; i++) { 609 // this is the source associated with this image1274 // this is the source associated with this image 610 1275 pmSource *thisSource = sources->data[i]; 611 1276 612 // this is the "real" version of this source613 pmSource *source = thisSource->parent ? thisSource->parent : thisSource;1277 // this is the "real" version of this source 1278 pmSource *source = thisSource->parent ? thisSource->parent : thisSource; 614 1279 615 1280 // skip sources without measurements … … 639 1304 psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG", PS_DATA_F32, "Sigma in EXT y coordinate", yErr); 640 1305 641 float AxialRatio = NAN;642 float AxialTheta = NAN;643 pmSourceExtendedPars *extpars = source->extpars;644 if (extpars) {645 AxialRatio = extpars->axes.minor / extpars->axes.major;646 AxialTheta = extpars->axes.theta;647 }1306 float AxialRatio = NAN; 1307 float AxialTheta = NAN; 1308 pmSourceExtendedPars *extpars = source->extpars; 1309 if (extpars) { 1310 AxialRatio = extpars->axes.minor / extpars->axes.major; 1311 AxialTheta = extpars->axes.theta; 1312 } 648 1313 psMetadataAdd (row, PS_LIST_TAIL, "F25_ARATIO", PS_DATA_F32, "Axial Ratio of radial profile", AxialRatio); 649 1314 psMetadataAdd (row, PS_LIST_TAIL, "F25_THETA", PS_DATA_F32, "Angle of radial profile ellipse", AxialTheta); … … 651 1316 // Petrosian measurements 652 1317 // XXX insert header data: petrosian ref radius, flux ratio 653 // XXX check flags to see if Pet was measured1318 // XXX check flags to see if Pet was measured 654 1319 if (doPetrosian) { 655 pmSourceExtendedPars *extpars = source->extpars;1320 pmSourceExtendedPars *extpars = source->extpars; 656 1321 if (extpars) { 657 // XXX note that this mag is either calibrated or instrumental depending on existence of zero point658 float mag = (extpars->petrosianFlux > 0.0) ? -2.5*log10(extpars->petrosianFlux) + magOffset : NAN; // XXX zero point659 // NOTE EAM 20140806 : PETRO_MAG_ERR was inverted!! this allows for it to be repaired660 float magErr = (extpars->petrosianFlux > 0.0) ? extpars->petrosianFlux / extpars->petrosianFluxErr : NAN; // XXX zero point661 if (repairMagErrors) {662 // I need to add the kron error in quadrature becasue pet_error ignores the object flux663 float Krf = source->moments ? source->moments->KronFlux : NAN;664 float dKrf = source->moments ? source->moments->KronFluxErr : NAN;665 if (isfinite (Krf) && isfinite (dKrf)) {666 magErr = sqrt(PS_SQR(1.0 / magErr) + PS_SQR(dKrf / Krf));667 } else {668 magErr = 1.0 / magErr;669 }670 }1322 // XXX note that this mag is either calibrated or instrumental depending on existence of zero point 1323 float mag = (extpars->petrosianFlux > 0.0) ? -2.5*log10(extpars->petrosianFlux) + magOffset : NAN; // XXX zero point 1324 // NOTE EAM 20140806 : PETRO_MAG_ERR was inverted!! this allows for it to be repaired 1325 float magErr = (extpars->petrosianFlux > 0.0) ? extpars->petrosianFlux / extpars->petrosianFluxErr : NAN; // XXX zero point 1326 if (repairMagErrors) { 1327 // I need to add the kron error in quadrature becasue pet_error ignores the object flux 1328 float Krf = source->moments ? source->moments->KronFlux : NAN; 1329 float dKrf = source->moments ? source->moments->KronFluxErr : NAN; 1330 if (isfinite (Krf) && isfinite (dKrf)) { 1331 magErr = sqrt(PS_SQR(1.0 / magErr) + PS_SQR(dKrf / Krf)); 1332 } else { 1333 magErr = 1.0 / magErr; 1334 } 1335 } 671 1336 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG", PS_DATA_F32, "Petrosian Magnitude", mag); 672 1337 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR", PS_DATA_F32, "Petrosian Magnitude Error", magErr); … … 705 1370 // Flux Annuli (if we have extended source measurements, we have these. only optionally save them) 706 1371 if (doAnnuli) { 707 psVector *radSB = psVectorAlloc(radMin->n, PS_TYPE_F32);708 psVector *radFlux = psVectorAlloc(radMin->n, PS_TYPE_F32);709 psVector *radFill = psVectorAlloc(radMin->n, PS_TYPE_F32);710 psVectorInit (radSB, NAN);711 psVectorInit (radFlux, NAN);712 psVectorInit (radFill, NAN);713 if (!source->extpars) goto empty_annuli;714 if (!source->extpars->radProfile) goto empty_annuli;715 if (!source->extpars->radProfile->binSB) goto empty_annuli;716 psAssert (source->extpars->radProfile->binSum, "programming error");717 psAssert (source->extpars->radProfile->binFill, "programming error");718 psAssert (source->extpars->radProfile->binSB->n <= radFlux->n, "inconsistent vector lengths");719 psAssert (source->extpars->radProfile->binSum->n <= radFlux->n, "inconsistent vector lengths");720 psAssert (source->extpars->radProfile->binFill->n <= radFlux->n, "inconsistent vector lengths");721 722 // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux723 for (int j = 0; j < source->extpars->radProfile->binSB->n; j++) {724 radSB->data.F32[j] = source->extpars->radProfile->binSB->data.F32[j];725 radFlux->data.F32[j] = source->extpars->radProfile->binSum->data.F32[j];726 radFill->data.F32[j] = source->extpars->radProfile->binFill->data.F32[j];727 }728 729 empty_annuli:730 psMetadataAdd (row, PS_LIST_TAIL, "PROF_SB", PS_DATA_VECTOR, "mean surface brightness annuli", radSB);731 psMetadataAdd (row, PS_LIST_TAIL, "PROF_FLUX", PS_DATA_VECTOR, "flux within annuli", radFlux);732 psMetadataAdd (row, PS_LIST_TAIL, "PROF_FILL", PS_DATA_VECTOR, "fill factor of annuli", radFill);733 psFree (radSB);734 psFree (radFlux);735 psFree (radFill);736 }737 if (nRow < 0) {738 nRow = row->list->n;739 } else {740 psAssert (nRow == row->list->n, "inconsistent row lengths");741 }742 psArrayAdd (table, 100, row);743 psFree (row);1372 psVector *radSB = psVectorAlloc(radMin->n, PS_TYPE_F32); 1373 psVector *radFlux = psVectorAlloc(radMin->n, PS_TYPE_F32); 1374 psVector *radFill = psVectorAlloc(radMin->n, PS_TYPE_F32); 1375 psVectorInit (radSB, NAN); 1376 psVectorInit (radFlux, NAN); 1377 psVectorInit (radFill, NAN); 1378 if (!source->extpars) goto empty_annuli; 1379 if (!source->extpars->radProfile) goto empty_annuli; 1380 if (!source->extpars->radProfile->binSB) goto empty_annuli; 1381 psAssert (source->extpars->radProfile->binSum, "programming error"); 1382 psAssert (source->extpars->radProfile->binFill, "programming error"); 1383 psAssert (source->extpars->radProfile->binSB->n <= radFlux->n, "inconsistent vector lengths"); 1384 psAssert (source->extpars->radProfile->binSum->n <= radFlux->n, "inconsistent vector lengths"); 1385 psAssert (source->extpars->radProfile->binFill->n <= radFlux->n, "inconsistent vector lengths"); 1386 1387 // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux 1388 for (int j = 0; j < source->extpars->radProfile->binSB->n; j++) { 1389 radSB->data.F32[j] = source->extpars->radProfile->binSB->data.F32[j]; 1390 radFlux->data.F32[j] = source->extpars->radProfile->binSum->data.F32[j]; 1391 radFill->data.F32[j] = source->extpars->radProfile->binFill->data.F32[j]; 1392 } 1393 1394 empty_annuli: 1395 psMetadataAdd (row, PS_LIST_TAIL, "PROF_SB", PS_DATA_VECTOR, "mean surface brightness annuli", radSB); 1396 psMetadataAdd (row, PS_LIST_TAIL, "PROF_FLUX", PS_DATA_VECTOR, "flux within annuli", radFlux); 1397 psMetadataAdd (row, PS_LIST_TAIL, "PROF_FILL", PS_DATA_VECTOR, "fill factor of annuli", radFill); 1398 psFree (radSB); 1399 psFree (radFlux); 1400 psFree (radFill); 1401 } 1402 if (nRow < 0) { 1403 nRow = row->list->n; 1404 } else { 1405 psAssert (nRow == row->list->n, "inconsistent row lengths"); 1406 } 1407 psArrayAdd (table, 100, row); 1408 psFree (row); 744 1409 } 745 1410 746 1411 if (table->n == 0) { 747 if (!psFitsWriteBlank (fits, outhead, extname)) {748 psError(psErrorCodeLast(), false, "Unable to write empty sources file.");749 psFree(outhead);750 psFree(table);751 return false;752 }753 psFree (outhead);754 psFree (table);755 return true;1412 if (!psFitsWriteBlank (fits, outhead, extname)) { 1413 psError(psErrorCodeLast(), false, "Unable to write empty sources file."); 1414 psFree(outhead); 1415 psFree(table); 1416 return false; 1417 } 1418 psFree (outhead); 1419 psFree (table); 1420 return true; 756 1421 } 757 1422 758 1423 psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname); 759 1424 if (!psFitsWriteTable (fits, outhead, table, extname)) { 760 psError(psErrorCodeLast(), false, "writing ext data %s\n", extname);761 psFree (outhead);762 psFree(table);763 return false;1425 psError(psErrorCodeLast(), false, "writing ext data %s\n", extname); 1426 psFree (outhead); 1427 psFree(table); 1428 return false; 764 1429 } 765 1430 psFree (outhead); … … 885 1550 extpars->axes.theta = psMetadataLookupF32(&status, row, "F25_THETA"); 886 1551 887 // magErr may have been saved in inverted form1552 // magErr may have been saved in inverted form 888 1553 float mag = psMetadataLookupF32(&status, row, "PETRO_MAG"); 889 1554 float magErr = psMetadataLookupF32(&status, row, "PETRO_MAG_ERR"); 890 1555 if (isfinite(mag)) { 891 extpars->petrosianFlux = pow(10., (magOffset - mag) / 2.5);892 if (isfinite(magErr)) {893 if (repairMagErrors) {894 // I need to add the kron error in quadrature becasue pet_error ignores the object flux895 float Krf = source->moments ? source->moments->KronFlux : NAN;896 float dKrf = source->moments ? source->moments->KronFluxErr : NAN;897 if (isfinite (Krf) && isfinite (dKrf)) {898 magErr = 1.0 / sqrt(PS_SQR(magErr) - PS_SQR(dKrf / Krf));899 } else {900 magErr = 1.0 / magErr;901 }902 extpars->petrosianFluxErr = extpars->petrosianFlux * magErr;903 } else {904 extpars->petrosianFluxErr = extpars->petrosianFlux / magErr;905 }906 }907 }1556 extpars->petrosianFlux = pow(10., (magOffset - mag) / 2.5); 1557 if (isfinite(magErr)) { 1558 if (repairMagErrors) { 1559 // I need to add the kron error in quadrature becasue pet_error ignores the object flux 1560 float Krf = source->moments ? source->moments->KronFlux : NAN; 1561 float dKrf = source->moments ? source->moments->KronFluxErr : NAN; 1562 if (isfinite (Krf) && isfinite (dKrf)) { 1563 magErr = 1.0 / sqrt(PS_SQR(magErr) - PS_SQR(dKrf / Krf)); 1564 } else { 1565 magErr = 1.0 / magErr; 1566 } 1567 extpars->petrosianFluxErr = extpars->petrosianFlux * magErr; 1568 } else { 1569 extpars->petrosianFluxErr = extpars->petrosianFlux / magErr; 1570 } 1571 } 1572 } 908 1573 909 1574 extpars->petrosianRadius = psMetadataLookupF32(&status, row, "PETRO_RADIUS"); … … 973 1638 int nParamMax = 0; 974 1639 for (int i = 0; i < sources->n; i++) { 975 // this is the source associated with this image1640 // this is the source associated with this image 976 1641 pmSource *thisSource = sources->data[i]; 977 1642 978 // this is the "real" version of this source979 pmSource *source = thisSource->parent ? thisSource->parent : thisSource;1643 // this is the "real" version of this source 1644 pmSource *source = thisSource->parent ? thisSource->parent : thisSource; 980 1645 981 1646 if (source->modelFits == NULL) continue; … … 1004 1669 pmSource *thisSource = sources->data[i]; 1005 1670 1006 // this is the "real" version of this source1007 pmSource *source = thisSource->parent ? thisSource->parent : thisSource;1671 // this is the "real" version of this source 1672 pmSource *source = thisSource->parent ? thisSource->parent : thisSource; 1008 1673 1009 1674 // XXX if no model fits are saved, write out modelEXT? … … 1018 1683 1019 1684 // pmSourceExtFitPars *extPars = source->extFitPars->data[j]; 1020 // assert (extPars);1021 1022 // skip models which were not actually fitted1023 // XXX1024 if (model->flags & badModel) continue;1685 // assert (extPars); 1686 1687 // skip models which were not actually fitted 1688 // XXX 1689 if (model->flags & badModel) continue; 1025 1690 1026 1691 PAR = model->params->data.F32; … … 1029 1694 yPos = PAR[PM_PAR_YPOS]; 1030 1695 1031 // for the extended source models, we do not always fit the centroid in the non-linear fitting process1032 // current situation (hard-wired into psphotSourceFits.c:psphotFitPCM,1033 // SERSIC, DEV, EXP : X,Y not fitted (PCM and not PCM)1034 // TRAIL : X,Y are fitted1035 //1036 1037 // XXX this should be based on what happened, not on the model type1038 if (model->type == modelTypeTrail) {1039 xErr = dPAR[PM_PAR_XPOS];1040 yErr = dPAR[PM_PAR_YPOS];1041 } else {1042 // this is definitely an underestimate since it does not1043 // account for the extent of the source1044 xErr = fwhmMajor * model->magErr / 2.35;1045 yErr = fwhmMinor * model->magErr / 2.35;1046 }1047 1048 @>PS1_DV2,>PS1_SV3@ psSphere ptSky = {0.0, 0.0, 0.0, 0.0};1049 @>PS1_DV2,>PS1_SV3@ float posAngle = 0.0;1050 @>PS1_DV2,>PS1_SV3@ float pltScale = 0.0;1051 @>PS1_DV2,>PS1_SV3@ pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos);1052 @>PS1_DV2,>PS1_SV3@ double raPos = ptSky.r*PS_DEG_RAD;1053 @>PS1_DV2,>PS1_SV3@ double decPos = ptSky.d*PS_DEG_RAD;1054 @>PS1_DV2,>PS1_SV3@ posAngle *= PS_DEG_RAD;1055 @>PS1_DV2,>PS1_SV3@ pltScale *= PS_DEG_RAD*3600.0;1056 1057 float kronFlux = source->moments ? source->moments->KronFlux : NAN;1058 float kronMag = isfinite(kronFlux) ? -2.5*log10(kronFlux) : NAN;1696 // for the extended source models, we do not always fit the centroid in the non-linear fitting process 1697 // current situation (hard-wired into psphotSourceFits.c:psphotFitPCM, 1698 // SERSIC, DEV, EXP : X,Y not fitted (PCM and not PCM) 1699 // TRAIL : X,Y are fitted 1700 // 1701 1702 // XXX this should be based on what happened, not on the model type 1703 if (model->type == modelTypeTrail) { 1704 xErr = dPAR[PM_PAR_XPOS]; 1705 yErr = dPAR[PM_PAR_YPOS]; 1706 } else { 1707 // this is definitely an underestimate since it does not 1708 // account for the extent of the source 1709 xErr = fwhmMajor * model->magErr / 2.35; 1710 yErr = fwhmMinor * model->magErr / 2.35; 1711 } 1712 1713 @>PS1_DV2,>PS1_SV3@ psSphere ptSky = {0.0, 0.0, 0.0, 0.0}; 1714 @>PS1_DV2,>PS1_SV3@ float posAngle = 0.0; 1715 @>PS1_DV2,>PS1_SV3@ float pltScale = 0.0; 1716 @>PS1_DV2,>PS1_SV3@ pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos); 1717 @>PS1_DV2,>PS1_SV3@ double raPos = ptSky.r*PS_DEG_RAD; 1718 @>PS1_DV2,>PS1_SV3@ double decPos = ptSky.d*PS_DEG_RAD; 1719 @>PS1_DV2,>PS1_SV3@ posAngle *= PS_DEG_RAD; 1720 @>PS1_DV2,>PS1_SV3@ pltScale *= PS_DEG_RAD*3600.0; 1721 1722 float kronFlux = source->moments ? source->moments->KronFlux : NAN; 1723 float kronMag = isfinite(kronFlux) ? -2.5*log10(kronFlux) : NAN; 1059 1724 1060 1725 row = psMetadataAlloc (); 1061 1726 1062 // the psMetadataAdd entry and the double quotes are used by grep to select the output fields for automatic documentation1063 // This set of psMetadataAdd Entries marks the "----" "Start of the XFIT segment"1727 // the psMetadataAdd entry and the double quotes are used by grep to select the output fields for automatic documentation 1728 // This set of psMetadataAdd Entries marks the "----" "Start of the XFIT segment" 1064 1729 psMetadataAddU32 (row, PS_LIST_TAIL, "IPP_IDET", 0, "IPP detection identifier index", source->seq); 1065 1730 psMetadataAddF32 (row, PS_LIST_TAIL, "X_EXT", 0, "EXT model x coordinate", xPos); … … 1070 1735 @>PS1_DV2,>PS1_SV3@ psMetadataAddF32 (row, PS_LIST_TAIL, "RA_EXT", 0, "EXT model ra coordinate", raPos); 1071 1736 @>PS1_DV2,>PS1_SV3@ psMetadataAddF32 (row, PS_LIST_TAIL, "DEC_EXT", 0, "EXT model dec coordinate", decPos); 1072 @>PS1_DV2@ float instFlux = isfinite(model->mag) ? pow(10.0, -0.4*model->mag) : NAN;1073 @>PS1_DV2@ psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_FLUX", 0, "EXT fit instrumental counts", instFlux);1737 @>PS1_DV2@ float instFlux = isfinite(model->mag) ? pow(10.0, -0.4*model->mag) : NAN; 1738 @>PS1_DV2@ psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_FLUX", 0, "EXT fit instrumental counts", instFlux); 1074 1739 1075 1740 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_MAG", 0, "EXT fit instrumental magnitude", model->mag); 1076 1741 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_MAG_SIG", 0, "Sigma of PSF instrumental magnitude", model->magErr); 1077 1742 1078 @>PS1_DV2@ float calMag = isfinite(magOffset) ? model->mag + magOffset : NAN;1079 @>PS1_DV2@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_CAL_MAG", PS_DATA_F32, "EXT Magnitude using supplied calibration", calMag);1080 @>PS1_DV2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_CHISQ", PS_DATA_F32, "EXT Model Chisq", model->chisq);1081 @>PS1_DV2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_NDOF", PS_DATA_S32, "EXT Model num degrees of freedom", model->nDOF);1082 @>PS1_SV1,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_MODEL_TYPE", PS_DATA_S32, "type for chosen EXT_MODEL", source->modelEXT ? source->modelEXT->type : -1);1083 1084 // EAM : adding for PV2 outputs:1085 @>PS1_SV1@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_FLAGS", PS_DATA_S16, "model fit flags (pmModelStatus)", model->flags);1743 @>PS1_DV2@ float calMag = isfinite(magOffset) ? model->mag + magOffset : NAN; 1744 @>PS1_DV2@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_CAL_MAG", PS_DATA_F32, "EXT Magnitude using supplied calibration", calMag); 1745 @>PS1_DV2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_CHISQ", PS_DATA_F32, "EXT Model Chisq", model->chisq); 1746 @>PS1_DV2,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_NDOF", PS_DATA_S32, "EXT Model num degrees of freedom", model->nDOF); 1747 @>PS1_SV1,PS1_SV?@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_MODEL_TYPE", PS_DATA_S32, "type for chosen EXT_MODEL", source->modelEXT ? source->modelEXT->type : -1); 1748 1749 // EAM : adding for PV2 outputs: 1750 @>PS1_SV1@ psMetadataAdd (row, PS_LIST_TAIL, "EXT_FLAGS", PS_DATA_S16, "model fit flags (pmModelStatus)", model->flags); 1086 1751 1087 1752 @>PS1_DV2@ psMetadataAddF32 (row, PS_LIST_TAIL, "POSANGLE", 0, "position angle at source (degrees)", posAngle); 1088 @>PS1_DV2@ psMetadataAddF32 (row, PS_LIST_TAIL, "PLTSCALE", 0, "plate scale at source (arcsec/pixel)", pltScale);1753 @>PS1_DV2@ psMetadataAddF32 (row, PS_LIST_TAIL, "PLTSCALE", 0, "plate scale at source (arcsec/pixel)", pltScale); 1089 1754 1090 1755 // psMetadataAddF32 (row, PS_LIST_TAIL, "MOMENTS_XX", 0, "second moment in x", extPars->Mxx); … … 1103 1768 1104 1769 // XXX these should be major and minor, not 'x' and 'y' 1105 if (model->type == pmModelClassGetType("PS_MODEL_TRAIL")) {1106 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ", 0, "EXT width (major axis), length for trail", PAR[PM_PAR_LENGTH]);1107 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN", 0, "EXT width (minor axis), sigma for trail", PAR[PM_PAR_SIGMA]); // this is not fitted1108 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA", 0, "EXT orientation angle", PAR[PM_PAR_THETA]);1109 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ_ERR",0, "EXT width error (major axis)", dPAR[PM_PAR_LENGTH]);1110 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN_ERR",0, "EXT width error (minor axis)", NAN); // this is not fitted, so error is NAN1111 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA_ERR", 0, "EXT orientation angle (error)", dPAR[PM_PAR_THETA]);1112 } else {1113 if (!isfinite(PAR[PM_PAR_SXX]) || !isfinite(PAR[PM_PAR_SYY]) || !isfinite(PAR[PM_PAR_SXY])) {1114 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ", 0, "EXT width (SXX, isnan)", PAR[PM_PAR_SXX]);1115 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN", 0, "EXT width (SYY, isnan)", PAR[PM_PAR_SYY]);1116 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA", 0, "EXT angle (SXY, isnan)", PAR[PM_PAR_SXY]);1117 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ_ERR", 0, "EXT width err (SXX, isnan)", dPAR[PM_PAR_SXX]);1118 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN_ERR", 0, "EXT width err (SYY, isnan)", dPAR[PM_PAR_SYY]);1119 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA_ERR", 0, "EXT angle err (SXY, isnan)", dPAR[PM_PAR_SXY]);1120 } else {1121 psEllipseAxes axes = pmPSF_ModelToAxes (PAR, model->class->useReff);1122 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ", 0, "EXT width (major axis), length for trail", axes.major);1123 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN", 0, "EXT width (minor axis), sigma for trail", axes.minor);1124 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA", 0, "EXT orientation angle", axes.theta);1125 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ_ERR",0, "EXT width error (major axis)", dPAR[PM_PAR_SXX]);1126 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN_ERR",0, "EXT width error (minor axis)", dPAR[PM_PAR_SYY]);1127 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA_ERR", 0, "EXT orientation angle (error)", dPAR[PM_PAR_SXY]);1128 }1129 }1770 if (model->type == pmModelClassGetType("PS_MODEL_TRAIL")) { 1771 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ", 0, "EXT width (major axis), length for trail", PAR[PM_PAR_LENGTH]); 1772 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN", 0, "EXT width (minor axis), sigma for trail", PAR[PM_PAR_SIGMA]); // this is not fitted 1773 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA", 0, "EXT orientation angle", PAR[PM_PAR_THETA]); 1774 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ_ERR",0, "EXT width error (major axis)", dPAR[PM_PAR_LENGTH]); 1775 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN_ERR",0, "EXT width error (minor axis)", NAN); // this is not fitted, so error is NAN 1776 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA_ERR", 0, "EXT orientation angle (error)", dPAR[PM_PAR_THETA]); 1777 } else { 1778 if (!isfinite(PAR[PM_PAR_SXX]) || !isfinite(PAR[PM_PAR_SYY]) || !isfinite(PAR[PM_PAR_SXY])) { 1779 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ", 0, "EXT width (SXX, isnan)", PAR[PM_PAR_SXX]); 1780 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN", 0, "EXT width (SYY, isnan)", PAR[PM_PAR_SYY]); 1781 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA", 0, "EXT angle (SXY, isnan)", PAR[PM_PAR_SXY]); 1782 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ_ERR", 0, "EXT width err (SXX, isnan)", dPAR[PM_PAR_SXX]); 1783 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN_ERR", 0, "EXT width err (SYY, isnan)", dPAR[PM_PAR_SYY]); 1784 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA_ERR", 0, "EXT angle err (SXY, isnan)", dPAR[PM_PAR_SXY]); 1785 } else { 1786 psEllipseAxes axes = pmPSF_ModelToAxes (PAR, model->class->useReff); 1787 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ", 0, "EXT width (major axis), length for trail", axes.major); 1788 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN", 0, "EXT width (minor axis), sigma for trail", axes.minor); 1789 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA", 0, "EXT orientation angle", axes.theta); 1790 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ_ERR",0, "EXT width error (major axis)", dPAR[PM_PAR_SXX]); 1791 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN_ERR",0, "EXT width error (minor axis)", dPAR[PM_PAR_SYY]); 1792 psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA_ERR", 0, "EXT orientation angle (error)", dPAR[PM_PAR_SXY]); 1793 } 1794 } 1130 1795 1131 1796 // write out the other generic parameters … … 1140 1805 1141 1806 snprintf (name, 64, "EXT_PAR_%02d", k); 1142 1807 1143 1808 if (k < model->params->n) { 1144 1809 psMetadataAddF32 (row, PS_LIST_TAIL, name, 0, "", model->params->data.F32[k]); … … 1148 1813 } 1149 1814 1150 // optionally, write out the covariance matrix values1151 // XXX do I need to pad this to match the biggest covar matrix?1152 if (false && model->covar) {1153 for (int iy = 0; iy < model->covar->numCols; iy++) {1154 for (int ix = iy; ix < model->covar->numCols; ix++) {1155 snprintf (name, 64, "EXT_COVAR_%02d_%02d", iy, ix);1156 psMetadataAddF32 (row, PS_LIST_TAIL, name, 0, "", model->covar->data.F32[iy][ix]);1157 1158 }1159 }1160 }1815 // optionally, write out the covariance matrix values 1816 // XXX do I need to pad this to match the biggest covar matrix? 1817 if (false && model->covar) { 1818 for (int iy = 0; iy < model->covar->numCols; iy++) { 1819 for (int ix = iy; ix < model->covar->numCols; ix++) { 1820 snprintf (name, 64, "EXT_COVAR_%02d_%02d", iy, ix); 1821 psMetadataAddF32 (row, PS_LIST_TAIL, name, 0, "", model->covar->data.F32[iy][ix]); 1822 1823 } 1824 } 1825 } 1161 1826 psArrayAdd (table, 100, row); 1162 1827 psFree (row); … … 1280 1945 PAR[7] = psMetadataLookupF32(&status, row, "EXT_PAR_07"); 1281 1946 // XXX add an error: 1282 // dPAR[7] = psMetadataLookupF32(&status, row, "EXT_PAR_07_");1283 } 1284 1285 // NOTE: we no longer write out the covariance matrix1286 if (false) {1287 // read the covariance matrix1288 int nparams = model->params->n;1289 psImage *covar = psImageAlloc(nparams, nparams, PS_TYPE_F32);1290 for (int y = 0; y < nparams; y++) {1291 for (int x = 0; x < nparams; x++) {1292 char name[64];1293 snprintf(name, 64, "EXT_COVAR_%02d_%02d", y, x);1294 covar->data.F32[y][x] = psMetadataLookupF32(&status, row, name);1295 }1296 }1297 model->covar = covar;1298 }1299 1300 // we are only saving the values stored in dPAR[SXX,etc]1947 // dPAR[7] = psMetadataLookupF32(&status, row, "EXT_PAR_07_"); 1948 } 1949 1950 // NOTE: we no longer write out the covariance matrix 1951 if (false) { 1952 // read the covariance matrix 1953 int nparams = model->params->n; 1954 psImage *covar = psImageAlloc(nparams, nparams, PS_TYPE_F32); 1955 for (int y = 0; y < nparams; y++) { 1956 for (int x = 0; x < nparams; x++) { 1957 char name[64]; 1958 snprintf(name, 64, "EXT_COVAR_%02d_%02d", y, x); 1959 covar->data.F32[y][x] = psMetadataLookupF32(&status, row, name); 1960 } 1961 } 1962 model->covar = covar; 1963 } 1964 1965 // we are only saving the values stored in dPAR[SXX,etc] 1301 1966 dPAR[PM_PAR_SXX] = psMetadataLookupF32(&status, row, "EXT_WIDTH_MAJ_ERR"); 1302 1967 dPAR[PM_PAR_SYY] = psMetadataLookupF32(&status, row, "EXT_WIDTH_MIN_ERR"); 1303 1968 dPAR[PM_PAR_SXY] = psMetadataLookupF32(&status, row, "EXT_THETA_ERR"); 1304 1969 1305 // other parameters that we need to read1970 // other parameters that we need to read 1306 1971 PAR[PM_PAR_SKY] = psMetadataLookupF32(&status, row, "SKY_EXT"); 1307 1972 … … 1341 2006 // perform full non-linear fits / extended source analysis? 1342 2007 if (!psMetadataLookupBool (&status, recipe, "RADIAL_APERTURES")) { 1343 psLogMsg ("psphot", PS_LOG_INFO, "radial apertures were not measured, skipping\n");1344 return true;2008 psLogMsg ("psphot", PS_LOG_INFO, "radial apertures were not measured, skipping\n"); 2009 return true; 1345 2010 } 1346 2011 … … 1385 2050 for (int i = 0; i < sources->n; i++) { 1386 2051 1387 // this is the source associated with this image2052 // this is the source associated with this image 1388 2053 pmSource *thisSource = sources->data[i]; 1389 2054 1390 // this is the "real" version of this source1391 pmSource *source = thisSource->parent ? thisSource->parent : thisSource;2055 // this is the "real" version of this source 2056 pmSource *source = thisSource->parent ? thisSource->parent : thisSource; 1392 2057 1393 2058 // skip sources without radial aper measurements (or insufficient) 1394 if (source->radialAper == NULL) continue;2059 if (source->radialAper == NULL) continue; 1395 2060 1396 2061 // psAssert (source->radialAper->n == fwhmValues->n, "inconsistent radial aperture set"); 1397 2062 1398 for (int entry = 0; entry < source->radialAper->n; entry++) {1399 1400 // choose the convolved EXT model, if available, otherwise the simple one1401 pmSourceRadialApertures *radialAper = source->radialAper->data[entry];1402 assert (radialAper);1403 1404 if (pmSourcePositionUseMoments(source)) {1405 xPos = source->moments->Mx;1406 yPos = source->moments->My;1407 } else {1408 xPos = source->peak->xf;1409 yPos = source->peak->yf;1410 }1411 1412 row = psMetadataAlloc ();1413 1414 // XXX we are not writing out the mode (flags) or the type (psf, ext, etc)1415 // the psMetadataAdd entry and the double quotes are used by grep to select the output fields for automatic documentation1416 // This set of psMetadataAdd Entries marks the "----" "Start of the XRAD segment"1417 psMetadataAddU32 (row, PS_LIST_TAIL, "IPP_IDET", 0, "IPP detection identifier index", source->seq);1418 psMetadataAddF32 (row, PS_LIST_TAIL, "X_APER", 0, "Center of aperture measurements", xPos);1419 psMetadataAddF32 (row, PS_LIST_TAIL, "Y_APER", 0, "Center of aperture measurements", yPos);1420 if (fwhmValues) {1421 psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_FWHM", 0, "FWHM of matched PSF", fwhmValues->data.F32[entry]);1422 } else {1423 psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_FWHM", 0, "image is not FWHM-matched", NAN);1424 }1425 1426 // XXX if we have raw radial apertures, write them out here1427 psVector *radFlux = psVectorAlloc(radMax->n, PS_TYPE_F32);1428 psVector *radFluxErr = psVectorAlloc(radMax->n, PS_TYPE_F32);1429 psVector *radFill = psVectorAlloc(radMax->n, PS_TYPE_F32);1430 psVector *radFluxStdev = psVectorAlloc(radMax->n, PS_TYPE_F32);1431 psVectorInit (radFlux, NAN);1432 psVectorInit (radFluxErr, NAN);1433 psVectorInit (radFill, NAN);1434 if (!radialAper->flux) goto write_annuli;1435 if (!radialAper->fill) goto write_annuli;1436 psAssert (radialAper->flux->n <= radFlux->n, "inconsistent vector lengths");1437 psAssert (radialAper->fill->n <= radFlux->n, "inconsistent vector lengths");1438 1439 // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux1440 for (int j = 0; j < radialAper->flux->n; j++) {1441 radFlux->data.F32[j] = radialAper->flux->data.F32[j];1442 radFluxErr->data.F32[j] = radialAper->fluxErr->data.F32[j];1443 radFluxStdev->data.F32[j] = radialAper->fluxStdev->data.F32[j];1444 radFill->data.F32[j] = radialAper->fill->data.F32[j];1445 }1446 1447 write_annuli:1448 psMetadataAddVector (row, PS_LIST_TAIL, "APER_FLUX", PS_META_REPLACE, "flux within annuli", radFlux);1449 psMetadataAddVector (row, PS_LIST_TAIL, "APER_FLUX_ERR", PS_META_REPLACE, "flux error in annuli", radFluxErr);1450 psMetadataAddVector (row, PS_LIST_TAIL, "APER_FLUX_STDEV", PS_META_REPLACE, "flux standard deviation", radFluxStdev);1451 psMetadataAddVector (row, PS_LIST_TAIL, "APER_FILL", PS_META_REPLACE, "fill factor of annuli", radFill);1452 psFree (radFlux);1453 psFree (radFluxErr);1454 psFree (radFluxStdev);1455 psFree (radFill);1456 1457 psArrayAdd (table, 100, row);1458 psFree (row);1459 }2063 for (int entry = 0; entry < source->radialAper->n; entry++) { 2064 2065 // choose the convolved EXT model, if available, otherwise the simple one 2066 pmSourceRadialApertures *radialAper = source->radialAper->data[entry]; 2067 assert (radialAper); 2068 2069 if (pmSourcePositionUseMoments(source)) { 2070 xPos = source->moments->Mx; 2071 yPos = source->moments->My; 2072 } else { 2073 xPos = source->peak->xf; 2074 yPos = source->peak->yf; 2075 } 2076 2077 row = psMetadataAlloc (); 2078 2079 // XXX we are not writing out the mode (flags) or the type (psf, ext, etc) 2080 // the psMetadataAdd entry and the double quotes are used by grep to select the output fields for automatic documentation 2081 // This set of psMetadataAdd Entries marks the "----" "Start of the XRAD segment" 2082 psMetadataAddU32 (row, PS_LIST_TAIL, "IPP_IDET", 0, "IPP detection identifier index", source->seq); 2083 psMetadataAddF32 (row, PS_LIST_TAIL, "X_APER", 0, "Center of aperture measurements", xPos); 2084 psMetadataAddF32 (row, PS_LIST_TAIL, "Y_APER", 0, "Center of aperture measurements", yPos); 2085 if (fwhmValues) { 2086 psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_FWHM", 0, "FWHM of matched PSF", fwhmValues->data.F32[entry]); 2087 } else { 2088 psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_FWHM", 0, "image is not FWHM-matched", NAN); 2089 } 2090 2091 // XXX if we have raw radial apertures, write them out here 2092 psVector *radFlux = psVectorAlloc(radMax->n, PS_TYPE_F32); 2093 psVector *radFluxErr = psVectorAlloc(radMax->n, PS_TYPE_F32); 2094 psVector *radFill = psVectorAlloc(radMax->n, PS_TYPE_F32); 2095 psVector *radFluxStdev = psVectorAlloc(radMax->n, PS_TYPE_F32); 2096 psVectorInit (radFlux, NAN); 2097 psVectorInit (radFluxErr, NAN); 2098 psVectorInit (radFill, NAN); 2099 if (!radialAper->flux) goto write_annuli; 2100 if (!radialAper->fill) goto write_annuli; 2101 psAssert (radialAper->flux->n <= radFlux->n, "inconsistent vector lengths"); 2102 psAssert (radialAper->fill->n <= radFlux->n, "inconsistent vector lengths"); 2103 2104 // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux 2105 for (int j = 0; j < radialAper->flux->n; j++) { 2106 radFlux->data.F32[j] = radialAper->flux->data.F32[j]; 2107 radFluxErr->data.F32[j] = radialAper->fluxErr->data.F32[j]; 2108 radFluxStdev->data.F32[j] = radialAper->fluxStdev->data.F32[j]; 2109 radFill->data.F32[j] = radialAper->fill->data.F32[j]; 2110 } 2111 2112 write_annuli: 2113 psMetadataAddVector (row, PS_LIST_TAIL, "APER_FLUX", PS_META_REPLACE, "flux within annuli", radFlux); 2114 psMetadataAddVector (row, PS_LIST_TAIL, "APER_FLUX_ERR", PS_META_REPLACE, "flux error in annuli", radFluxErr); 2115 psMetadataAddVector (row, PS_LIST_TAIL, "APER_FLUX_STDEV", PS_META_REPLACE, "flux standard deviation", radFluxStdev); 2116 psMetadataAddVector (row, PS_LIST_TAIL, "APER_FILL", PS_META_REPLACE, "fill factor of annuli", radFill); 2117 psFree (radFlux); 2118 psFree (radFluxErr); 2119 psFree (radFluxStdev); 2120 psFree (radFill); 2121 2122 psArrayAdd (table, 100, row); 2123 psFree (row); 2124 } 1460 2125 } 1461 2126 … … 1581 2246 // perform full non-linear fits / extended source analysis? 1582 2247 if (!psMetadataLookupBool (&status, recipe, "GALAXY_SHAPES")) { 1583 psLogMsg ("psphot", PS_LOG_INFO, "galaxy shapes were not measured, skipping\n");1584 return true;2248 psLogMsg ("psphot", PS_LOG_INFO, "galaxy shapes were not measured, skipping\n"); 2249 return true; 1585 2250 } 1586 2251 … … 1609 2274 pmSource *thisSource = sources->data[i]; 1610 2275 1611 // this is the "real" version of this source1612 pmSource *source = thisSource->parent ? thisSource->parent : thisSource;1613 1614 // if we did not fit the galaxy model, modelFits will be NULL2276 // this is the "real" version of this source 2277 pmSource *source = thisSource->parent ? thisSource->parent : thisSource; 2278 2279 // if we did not fit the galaxy model, modelFits will be NULL 1615 2280 if (source->modelFits == NULL) continue; 1616 2281 1617 // if we did not fit the galaxy model, galaxyFits will also be NULL2282 // if we did not fit the galaxy model, galaxyFits will also be NULL 1618 2283 if (source->galaxyFits == NULL) continue; 1619 2284 -
trunk/psModules/src/objects/pmSourceIO_Ghosts.c
r41391 r41892 136 136 pmFPAview *view = pmFPAviewAlloc (0); 137 137 138 // We need to check whether we are dealing with an old style ghost_model, or a new style model. Check if the mirror_rad polynomial exists138 // We need to check whether we are dealing with an old style ghost_model, or a new style model. Check if the mirror_rad polynomial exists 139 139 float mirCheck = 0; 140 140 md = psMetadataLookupMetadata (&status, ghostModel, "GHOST.MIRROR.RAD"); … … 153 153 GET_1D_POLY ("GHOST.INNER.MINOR", innerMinor); 154 154 155 156 155 // select the input astrometry data (also carries the refstars) 157 156 pmFPAfile *astrom = psMetadataLookupPtr (NULL, config->files, "PSASTRO.INPUT"); … … 211 210 double theta0 = atan2(ref->FP->y,ref->FP->x); 212 211 213 if(mirCheck) { 212 // EAM: XXX we should just use the existence of mirrorRad (!= NULL) instead of carrying a different bool 213 if (mirCheck) { 214 214 //TdB: first mirror the reference star positions (around the 0,0 pixel) using the radial offset coefficients and the ghost/star angle 215 215 double ghost_offset_rad = psPolynomial1DEval (mirrorRad, rSrc); … … 220 220 ghost->FP->x = ghost_x_fpa_mirror + psPolynomial2DEval(centerX, ghost_x_fpa_mirror, ghost_y_fpa_mirror); 221 221 ghost->FP->y = ghost_y_fpa_mirror + psPolynomial2DEval(centerY, ghost_x_fpa_mirror, ghost_y_fpa_mirror); 222 } 223 if(!mirCheck) { 222 } else { 224 223 //Use the old-style ghost position determination 225 224 ghost->FP->x = -ref->FP->x + psPolynomial2DEval(centerX, -ref->FP->x, -ref->FP->y); … … 303 302 psFree (outerMajor); 304 303 psFree (outerMinor); 304 psFree (mirrorRad); 305 305 psFree (ghostModel); 306 306 psFree (view); … … 327 327 psFree (outerMajor); 328 328 psFree (outerMinor); 329 psFree (mirrorRad); 329 330 psFree (ghostModel); 330 331 psFree (view);
Note:
See TracChangeset
for help on using the changeset viewer.
