IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Dec 20, 2005, 12:41:06 PM (21 years ago)
Author:
gusciora
Message:

Added some of EAM's 3D and 4D fitting code.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/math/psMinimize.c

    r5655 r5818  
    1010 *  @author EAM, IfA
    1111 *
    12  *  @version $Revision: 1.147 $ $Name: not supported by cvs2svn $
    13  *  @date $Date: 2005-12-01 23:36:23 $
     12 *  @version $Revision: 1.148 $ $Name: not supported by cvs2svn $
     13 *  @date $Date: 2005-12-20 22:41:06 $
    1414 *
    1515 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    113113    }
    114114
     115    // XXX: Check error codes!
    115116    psGaussJordan(Alpha, Beta);
    116117    psFree(A);
     
    14411442}
    14421443
    1443 // here is the definition for BuildSums4D.  ifdef'ed away until it is used
    1444 // by psPolynomial4DFit..
    1445 # if (0)
    1446     /******************************************************************************
     1444/******************************************************************************
     1445BuildSums3D(sums, x, y, z, nXterm, nYterm, nZterm): this routine calculates the powers of
     1446input parameter "x", "y", and "z" between 0 and input parameter nXterms*2,
     1447nYterm*2, and nZterm*2.  The result is returned as a psImage sums.
     1448 *****************************************************************************/
     1449static psF64 ***BuildSums3D(
     1450    psF64 ***sums,
     1451    psF64 x,
     1452    psF64 y,
     1453    psF64 z,
     1454    psS32 nXterm,
     1455    psS32 nYterm,
     1456    psS32 nZterm)
     1457{
     1458    psS32 nXsum = 0;
     1459    psS32 nYsum = 0;
     1460    psS32 nZsum = 0;
     1461    psF64 xSum = 1.0;
     1462    psF64 ySum = 1.0;
     1463    psF64 zSum = 1.0;
     1464
     1465    nXsum = 2*nXterm;
     1466    nYsum = 2*nYterm;
     1467    nZsum = 2*nZterm;
     1468    if (sums == NULL) {
     1469        sums = (psF64 ***) psAlloc (nXsum*sizeof(psF64));
     1470        for (int i = 0; i < nXsum; i++) {
     1471            sums[i] = (psF64 **) psAlloc (nYsum*sizeof(psF64));
     1472            for (int j = 0; j < nYsum; j++) {
     1473                sums[i][j] = (psF64 *) psAlloc (nZsum*sizeof(psF64));
     1474            }
     1475        }
     1476    }
     1477    // careful with this function: there is no size checking and realloc for reuse
     1478
     1479    zSum = 1.0;
     1480    for (int k = 0; k < nZsum; k++) {
     1481        ySum = zSum;
     1482        for (int j = 0; j < nYsum; j++) {
     1483            xSum = ySum;
     1484            for (int i = 0; i < nXsum; i++) {
     1485                sums[i][j][k] = xSum;
     1486                xSum *= x;
     1487            }
     1488            ySum *= y;
     1489        }
     1490        zSum *= z;
     1491    }
     1492    return (sums);
     1493}
     1494
     1495/******************************************************************************
    14471496    BuildSums4D(sums, x, y, z, t, nXterm, nYterm, nZterm, nTterm). equiv to
    14481497    BuildSums2D(). The result is returned as a double ****
    1449      *****************************************************************************/
    1450     static double ****BuildSums4D(
    1451         psF64 ****sums,
    1452         psF64 x,
    1453         psF64 y,
    1454         psF64 z,
    1455         psF64 t,
    1456         psS32 nXterm,
    1457         psS32 nYterm,
    1458         psS32 nZterm,
    1459         psS32 nTterm)
     1498*****************************************************************************/
     1499static psF64 ****BuildSums4D(
     1500    psF64 ****sums,
     1501    psF64 x,
     1502    psF64 y,
     1503    psF64 z,
     1504    psF64 t,
     1505    psS32 nXterm,
     1506    psS32 nYterm,
     1507    psS32 nZterm,
     1508    psS32 nTterm)
    14601509{
    14611510    psS32 nXsum = 0;
     
    15051554    return (sums);
    15061555}
    1507 # endif /* BuildSums4D */
    15081556
    15091557/******************************************************************************
     
    15561604
    15571605/******************************************************************************
    1558 vectorFitPolynomial1DCheb():  This routine will fit a Chebyshev polynomial of
    1559 degree myPoly to the data points (x, y) and return the coefficients of that
     1606vectorFitPolynomial1DChebSlow():  This routine will fit a Chebyshev polynomial
     1607of degree myPoly to the data points (x, y) and return the coefficients of that
    15601608polynomial.
     1609 
     1610    NOTE: We currently have implemented two algorithms.  This one is
     1611    non-standard.  It ignores the orthogonal properties of the Chebyshev
     1612    polys, and their known zero values.  Instead, we do build a system of
     1613    linear equations based on minimizing the chi-squared for all data points
     1614    and we then solve those equations.  This method is significantly slower
     1615    than the other algorithm.  It was explicitly requested that we implement
     1616    this algorithm.
    15611617 
    15621618XXX: mask, maskValue, yErr are currently ignored.
     
    15641620XXX: Change arg order to that of the psLib function.
    15651621*****************************************************************************/
    1566 static psPolynomial1D *vectorFitPolynomial1DCheby(
     1622static psPolynomial1D *vectorFitPolynomial1DChebySlow(
    15671623    psPolynomial1D* myPoly,
    15681624    const psVector *mask,
     
    15721628    const psVector* x)
    15731629{
    1574     // XXX: these ASSERTS are redundant.
     1630    PS_ASSERT_POLY_NON_NULL(myPoly, NULL);
     1631    PS_ASSERT_INT_LARGER_THAN_OR_EQUAL(myPoly->nX, 0, NULL);
     1632    PS_ASSERT_VECTOR_NON_NULL(y, NULL);
     1633    PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, NULL);
     1634    if (yErr != NULL) {
     1635        PS_ASSERT_VECTORS_SIZE_EQUAL(y, yErr, NULL);
     1636        PS_ASSERT_VECTOR_TYPE(yErr, PS_TYPE_F64, NULL);
     1637    }
     1638    if (x != NULL) {
     1639        PS_ASSERT_VECTORS_SIZE_EQUAL(y, x, NULL);
     1640        PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, NULL);
     1641    }
     1642    psS32 NUM_POLY = myPoly->nX+1;
     1643    psS32 NUM_DATA = x->n;
     1644    psPolynomial1D **chebPolys = createChebyshevPolys(NUM_POLY);
     1645    if (0) {
     1646        for (psS32 j = 0; j < NUM_POLY; j++) {
     1647            PS_POLY_PRINT_1D(chebPolys[j]);
     1648        }
     1649    }
     1650
     1651    // Pre-compute the various Chebyshev polys T_i(x[j]) for all x[]
     1652    psImage *tMatrix = psImageAlloc(NUM_DATA, NUM_POLY, PS_TYPE_F64);
     1653    for (psS32 p = 0 ; p < NUM_POLY ; p++) {
     1654        for (psS32 d = 0 ; d < NUM_DATA ; d++) {
     1655            tMatrix->data.F64[p][d] = psPolynomial1DEval(chebPolys[p], x->data.F64[d]);
     1656        }
     1657    }
     1658
     1659    // Compute the A matrix
     1660    psImage *A = psImageAlloc(NUM_POLY, NUM_POLY, PS_TYPE_F64);
     1661    for (psS32 i = 0 ; i < NUM_POLY ; i++) {
     1662        for (psS32 j = 0 ; j < NUM_POLY ; j++) {
     1663            A->data.F64[i][j] = 0.0;
     1664            for (psS32 d = 0 ; d < NUM_DATA ; d++) {
     1665                A->data.F64[i][j]+= (tMatrix->data.F64[j][d] * tMatrix->data.F64[i][d]);
     1666            }
     1667        }
     1668        // This is because of the last term in: f(x) = SUM[c_i * T_i(x)]  -  c_0/2
     1669        for (psS32 d = 0 ; d < NUM_DATA ; d++) {
     1670            A->data.F64[i][0] -= (tMatrix->data.F64[i][d]/2.0);
     1671        }
     1672    }
     1673
     1674    // Compute the B vector
     1675    psVector *B = psVectorAlloc(NUM_POLY, PS_TYPE_F64);
     1676    for (psS32 i = 0 ; i < NUM_POLY ; i++) {
     1677        B->data.F64[i] = 0.0;
     1678        for (psS32 d = 0 ; d < NUM_DATA ; d++) {
     1679            B->data.F64[i] += (y->data.F64[d] * tMatrix->data.F64[i][d]);
     1680
     1681        }
     1682    }
     1683
     1684    // GaussJordan version
     1685    if (0) {
     1686        // does the solution in place
     1687        // XXX: Check error codes!
     1688        psGaussJordan (A, B);
     1689
     1690        // the first nTerm entries in B correspond directly to the desired
     1691        // polynomial coefficients.  this is only true for the 1D case
     1692        for (psS32 k = 0; k < NUM_POLY; k++) {
     1693            myPoly->coeff[k] = B->data.F64[k];
     1694        }
     1695    } else {
     1696        // LUD version of the fit
     1697        psImage *ALUD = NULL;
     1698        psVector* outPerm = NULL;
     1699        psVector* coeffs = NULL;
     1700
     1701        ALUD = psImageAlloc(NUM_POLY, NUM_POLY, PS_TYPE_F64);
     1702        ALUD = psMatrixLUD(ALUD, &outPerm, A);
     1703        coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
     1704        for (psS32 k = 0; k < NUM_POLY; k++) {
     1705            myPoly->coeff[k] = coeffs->data.F64[k];
     1706        }
     1707
     1708        psFree(ALUD);
     1709        psFree(coeffs);
     1710        psFree(outPerm);
     1711    }
     1712
     1713    psFree(A);
     1714    psFree(B);
     1715    psFree(tMatrix);
     1716    for (psS32 i=0;i<NUM_POLY;i++) {
     1717        psFree(chebPolys[i]);
     1718    }
     1719    psFree(chebPolys);
     1720
     1721    return(myPoly);
     1722}
     1723
     1724/******************************************************************************
     1725vectorFitPolynomial1DChebFast():  This routine will fit a Chebyshev polynomial
     1726of degree myPoly to the data points (x, y) and return the coefficients of that
     1727polynomial.
     1728 
     1729    NOTE: We currently have two algorithms.  This is standard method which
     1730    uses the orthogonal properties of the Chebyshev polys, and their known
     1731    zero values.  This is significantly faster than the chi-squared approach.
     1732 
     1733XXX: mask, maskValue, yErr are currently ignored.
     1734 
     1735XXX: Change arg order to that of the psLib function.
     1736 
     1737XXX: This function will not work properly if the x-vector does not fully span
     1738the [-1:1] interval.
     1739*****************************************************************************/
     1740static psPolynomial1D *vectorFitPolynomial1DChebyFast(
     1741    psPolynomial1D* myPoly,
     1742    const psVector *mask,
     1743    psMaskType maskValue,
     1744    const psVector* y,
     1745    const psVector* yErr,
     1746    const psVector* x)
     1747{
    15751748    PS_ASSERT_POLY_NON_NULL(myPoly, NULL);
    15761749    PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, NULL);
     
    16141787    for (psS32 i=0;i<n;i++) {
    16151788        // NR 5.8.4
     1789        // NR 5.8.4
    16161790        psF64 Y = cos(M_PI * (0.5 + ((psF32) i)) / ((psF32) n));
    16171791        psF64 X = (Y + bma + bpa) - 1.0;
     
    16201794        // We interpolate against the tabluated x,y vectors to determine the
    16211795        // function value at X.
    1622         fScalar = p_psVectorInterpolate((psVector *) x,
    1623                                         (psVector *) y,
    1624                                         3,
    1625                                         &tmpScalar);
    1626 
    1627         f->data.F64[i] = fScalar->data.F64;
    1628         psFree(fScalar);
     1796        // XXX: This is somewhat of a hack to handle cases where the x vector does
     1797        // not fully span the [-1.0:1.0] interval.  We set the values of f[] to the
     1798        // values of y[] at those endpoints.
     1799        // XXX: This only works if x[] is increasing.
     1800
     1801        if (X <= x->data.F64[0]) {
     1802            f->data.F64[i] = y->data.F64[0];
     1803        } else if (X >= x->data.F64[x->n-1]) {
     1804            f->data.F64[i] = y->data.F64[x->n-1];
     1805        } else {
     1806            fScalar = p_psVectorInterpolate((psVector *) x, (psVector *) y,
     1807                                            3, &tmpScalar);
     1808            f->data.F64[i] = fScalar->data.F64;
     1809            psFree(fScalar);
     1810        }
    16291811
    16301812        psTrace(".psLib.dataManip.vectorFitPolynomial1DCheby", 6,
     
    16501832    return(myPoly);
    16511833}
     1834
     1835
    16521836
    16531837/******************************************************************************
     
    17591943    if (0) {
    17601944        // does the solution in place
     1945        // XXX: Check error codes!
    17611946        psGaussJordan (A, B);
    17621947
     
    18592044            psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring mask and maskValue with Chebyshev polynomials.\n");
    18602045        }
     2046        if (fErr != NULL) {
     2047            psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring error vector with Chebyshev polynomials.\n");
     2048        }
    18612049        if (x == NULL) {
    18622050            // If x==NULL, create an x64 vector with x values set to (-1:1).
    18632051            PS_VECTOR_GEN_CHEBY_INDEX(x64, f64->n);
    18642052        }
    1865         // XXX: Change arg order.
    1866         // XXX: Must modify this routine so that x64 or fErr64 can be NULL.
    1867         poly = vectorFitPolynomial1DCheby(poly, NULL, 0, f64, fErr64, x64);
     2053
     2054        if (1) {
     2055            poly = vectorFitPolynomial1DChebySlow(poly, NULL, 0, f64, fErr64, x64);
     2056        } else {
     2057            poly = vectorFitPolynomial1DChebyFast(poly, NULL, 0, f64, fErr64, x64);
     2058        }
    18682059        if (x == NULL) {
    18692060            psFree(x64);
     
    21022293
    21032294    // does the solution in place
     2295    // XXX: Check error codes!
    21042296    psGaussJordan (A, B);
    21052297
     
    24752667}
    24762668
     2669
    24772670/******************************************************************************
    24782671 ******************************************************************************
    2479  3-D Vector Fitting Code.
     2672 3-D Vector Fit Code.
    24802673 ******************************************************************************
    24812674 *****************************************************************************/
     
    25262719    }
    25272720
    2528     psError(PS_ERR_UNKNOWN, true, "3-D Polynomial Fitting is not Implemented.\n");
    2529     return (NULL);
     2721    psImage    *A = NULL;
     2722    psVector   *B = NULL;
     2723    psF64 ***Sums = NULL;
     2724    psF64 wt;
     2725    psS32 nTerm;
     2726
     2727    // XXX:Watch for changes to the psPolys: nTerm != nOrder.
     2728    psS32 nXterm = 1 + myPoly->nX;
     2729    psS32 nYterm = 1 + myPoly->nY;
     2730    psS32 nZterm = 1 + myPoly->nZ;
     2731    nTerm = nXterm * nYterm * nZterm;
     2732
     2733    A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64);
     2734    B = psVectorAlloc(nTerm, PS_TYPE_F64);
     2735
     2736    // Initialize data structures.
     2737    psVectorInit (B, 0.0);
     2738    psImageInit (A, 0.0);
     2739
     2740    // Sums look like: 1, x, x^2, ... x^(2n+1), y, xy, x^2y, ... x^(2n+1)*y, ...
     2741
     2742    // Build the B and A data structs.
     2743    for (int k  = 0; k < x->n; k++) {
     2744        if ((mask != NULL) && (mask->data.U8[k] & maskValue)) {
     2745            continue;
     2746        }
     2747
     2748        Sums = BuildSums3D(Sums, x->data.F64[k], y->data.F64[k], z->data.F64[k], nXterm, nYterm, nZterm);
     2749
     2750        if (fErr == NULL) {
     2751            wt = 1.0;
     2752        } else {
     2753            // this filters fErr == 0 values
     2754            wt = (fErr->data.F64[k] == 0.0) ? 0.0 : 1.0 / PS_SQR(fErr->data.F64[k]);
     2755        }
     2756
     2757        // we could skip half of the array and assign at the end
     2758        // we must handle masked orders
     2759        for (int ix = 0; ix < nXterm; ix++) {
     2760            for (int iy = 0; iy < nYterm; iy++) {
     2761                for (int iz = 0; iz < nZterm; iz++) {
     2762                    if (myPoly->mask[ix][iy][iz])
     2763                        continue;
     2764                    int nx = ix+iy*nXterm+iz*nXterm*nYterm;
     2765                    B->data.F64[nx] += f->data.F64[k] * Sums[ix][iy][iz] * wt;
     2766                }
     2767            }
     2768        }
     2769
     2770        for (int ix = 0; ix < nXterm; ix++) {
     2771            for (int iy = 0; iy < nYterm; iy++) {
     2772                for (int iz = 0; iz < nZterm; iz++) {
     2773                    if (myPoly->mask[ix][iy][iz])
     2774                        continue;
     2775                    int nx = ix+iy*nXterm+iz*nXterm*nYterm;
     2776                    for (int jx = 0; jx < nXterm; jx++) {
     2777                        for (int jy = 0; jy < nYterm; jy++) {
     2778                            for (int jz = 0; jz < nZterm; jz++) {
     2779                                if (myPoly->mask[jx][jy][jz])
     2780                                    continue;
     2781                                int ny = jx+jy*nXterm+jz*nXterm*nYterm;
     2782                                A->data.F64[nx][ny] += Sums[ix+jx][iy+jy][iz+jz] * wt;
     2783                            }
     2784                        }
     2785                    }
     2786                }
     2787            }
     2788        }
     2789    }
     2790
     2791    for (int ix = 0; ix < nXterm; ix++) {
     2792        for (int iy = 0; iy < nYterm; iy++) {
     2793            for (int iz = 0; iz < nZterm; iz++) {
     2794                if (!myPoly->mask[ix][iy][iz])
     2795                    continue;
     2796                int nx = ix+iy*nXterm+iz*nXterm*nYterm;
     2797                B->data.F64[nx] = 0;
     2798                for (int jx = 0; jx < nXterm; jx++) {
     2799                    for (int jy = 0; jy < nYterm; jy++) {
     2800                        for (int jz = 0; jz < nZterm; jz++) {
     2801                            int ny = jx+jy*nXterm+jz*nXterm*nYterm;
     2802                            A->data.F64[nx][ny] = (nx == ny) ? 1 : 0;
     2803                        }
     2804                    }
     2805                }
     2806            }
     2807        }
     2808    }
     2809
     2810    //    PS_IMAGE_PRINT_F64(A);
     2811    //    PS_VECTOR_PRINT_F64(B);
     2812    // does the solution in place
     2813    if (false == psGaussJordan (A, B)) {
     2814        psFree(A);
     2815        psFree(B);
     2816
     2817        for (int ix = 0; ix < 2*nXterm; ix++) {
     2818            for (int iy = 0; iy < 2*nYterm; iy++) {
     2819                psFree(Sums[ix][iy]);
     2820            }
     2821            psFree(Sums[ix]);
     2822        }
     2823        psFree(Sums);
     2824        psError(PS_ERR_UNKNOWN, false, "Failed to perform GaussJordan elimination.\n");
     2825        return(NULL);
     2826    }
     2827
     2828    // select the appropriate solution entries
     2829    for (int ix = 0; ix < nXterm; ix++) {
     2830        for (int iy = 0; iy < nYterm; iy++) {
     2831            for (int iz = 0; iz < nZterm; iz++) {
     2832                int nx = ix+iy*nXterm+iz*nXterm*nYterm;
     2833                myPoly->coeff[ix][iy][iz] = B->data.F64[nx];
     2834                myPoly->coeffErr[ix][iy][iz] = sqrt(A->data.F64[nx][nx]);
     2835            }
     2836        }
     2837    }
     2838
     2839    psFree(A);
     2840    psFree(B);
     2841
     2842    for (int ix = 0; ix < 2*nXterm; ix++) {
     2843        for (int iy = 0; iy < 2*nYterm; iy++) {
     2844            psFree(Sums[ix][iy]);
     2845        }
     2846        psFree(Sums[ix]);
     2847    }
     2848    psFree(Sums);
     2849
     2850    psTrace(".psLib.dataManip.VectorFitPolynomial3DOrd", 4,
     2851            "---- VectorFitPolynomial3DOrd() begin ----\n");
     2852    return (myPoly);
    25302853}
    25312854
     
    25992922    PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, NULL);
    26002923    if (z->type.type != PS_TYPE_F64) {
    2601         PS_VECTOR_GEN_F64_FROM_F32(y64, z);
     2924        PS_VECTOR_GEN_F64_FROM_F32(z64, z);
    26022925    } else {
    26032926        z64 = (psVector *) z;
     
    27143037    PS_ASSERT_PTR_NON_NULL(stats, NULL);
    27153038    PS_ASSERT_VECTOR_NON_NULL(f, NULL);
    2716     PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F32, NULL);
     3039    PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, NULL);
    27173040    if (mask != NULL) {
    27183041        PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, NULL);
     
    27213044    PS_ASSERT_VECTOR_NON_NULL(x, NULL);
    27223045    PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, NULL);
    2723     PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F32, NULL);
     3046    PS_ASSERT_VECTOR_TYPE_F32_OR_F64(x, NULL);
    27243047    PS_ASSERT_VECTOR_NON_NULL(y, NULL);
    27253048    PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, NULL);
    2726     PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F32, NULL);
     3049    PS_ASSERT_VECTOR_TYPE_F32_OR_F64(y, NULL);
    27273050    PS_ASSERT_VECTOR_NON_NULL(f, NULL);
    2728     PS_ASSERT_VECTORS_SIZE_EQUAL(f, f, NULL);
    2729     PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F32, NULL);
     3051    // PS_ASSERT_VECTORS_SIZE_EQUAL(f, f, NULL);
     3052    // PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, NULL);
    27303053    if (fErr != NULL) {
    27313054        PS_ASSERT_VECTORS_SIZE_EQUAL(fErr, mask, NULL);
    2732         PS_ASSERT_VECTOR_TYPE(fErr, PS_TYPE_F32, NULL);
    2733     }
    2734 
    2735     psLogMsg(__func__, PS_LOG_WARN, "WARNING: This function has not been implemented.  Returning NULL.\n");
    2736     return(NULL);
     3055        PS_ASSERT_VECTOR_TYPE_F32_OR_F64(fErr, NULL);
     3056    }
     3057
     3058    // clipping range defined by min and max and/or clipSigma
     3059    float minClipSigma;
     3060    float maxClipSigma;
     3061    if (isfinite(stats->max)) {
     3062        maxClipSigma = fabs(stats->max);
     3063    } else {
     3064        maxClipSigma = fabs(stats->clipSigma);
     3065    }
     3066    if (isfinite(stats->min)) {
     3067        minClipSigma = fabs(stats->min);
     3068    } else {
     3069        minClipSigma = fabs(stats->clipSigma);
     3070    }
     3071    psVector *fit   = NULL;
     3072    psVector *resid = psVectorAlloc (x->n, PS_TYPE_F64);
     3073
     3074    // eventual expansion: user supplies one of various stats option pairs,
     3075    // eg (SAMPLE_MEAN | SAMPLE_STDEV) and the correct pair is used to
     3076    // evaluate the clipping sigma
     3077    // for now, for the SAMPLE_MEDIAN and SAMPLE_STDEV to be used
     3078    stats->options |= (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
     3079
     3080    for (int N = 0; N < stats->clipIter; N++) {
     3081        int Nkeep = 0;
     3082
     3083        poly = psVectorFitPolynomial3D (poly, mask, maskValue, f, fErr, x, y, z);
     3084        fit = psPolynomial3DEvalVector (poly, x, y, z);
     3085        resid = (psVector *) psBinaryOp (resid, (void *) f, "-", (void *) fit);
     3086
     3087        stats  = psVectorStats (stats, resid, NULL, mask, maskValue);
     3088        float minClipValue = -minClipSigma*stats->sampleStdev;
     3089        float maxClipValue = +maxClipSigma*stats->sampleStdev;
     3090        psTrace (".psphot.VectorClipFit", 5, "resid stats: %f +/- %f\n", stats->sampleMedian, stats->sampleStdev);
     3091        psTrace (".psphot.VectorClipFit", 5, "min clip: %f, max clip: %f\n", minClipValue, maxClipValue);
     3092
     3093        // set mask if pts are not valid
     3094        // we are masking out any point which is out of range
     3095        // recovery is not allowed with this scheme
     3096        for (int i = 0; i < resid->n; i++) {
     3097            if ((mask != NULL) && (mask->data.U8[i] & maskValue)) {
     3098                continue;
     3099            }
     3100            if (resid->data.F64[i] - stats->sampleMedian > maxClipValue) {
     3101                if (mask != NULL) {
     3102                    mask->data.U8[i] |= 0x01;
     3103                }
     3104                continue;
     3105            }
     3106            if (resid->data.F64[i] - stats->sampleMedian < minClipValue) {
     3107                if (mask != NULL) {
     3108                    mask->data.U8[i] |= 0x01;
     3109                }
     3110                continue;
     3111            }
     3112            Nkeep ++;
     3113        }
     3114
     3115        psTrace (".psphot.VectorClipFit", 4, "keeping %d of %d pts for fit\n",
     3116                 Nkeep, x->n);
     3117
     3118        psFree (fit);
     3119    }
     3120    // Free local temporary variables
     3121    psFree (resid);
     3122
     3123    if (poly == NULL) {
     3124        psError(PS_ERR_UNKNOWN, true, "Could not fit a polynomial to the data.  Returning NULL.\n");
     3125        return(NULL);
     3126    }
     3127    return(poly);
    27373128}
    2738 
    27393129
    27403130/******************************************************************************
     
    27923182    }
    27933183
    2794     psError(PS_ERR_UNKNOWN, true, "4-D Polynomial Fitting is not Implemented.\n");
    2795     return (NULL);
     3184    // I think this is 1 dimension down
     3185    psImage     *A = NULL;
     3186    psVector    *B = NULL;
     3187    psF64 ****Sums = NULL;
     3188    psF64 wt;
     3189    psS32 nTerm;
     3190
     3191    // XXX:Watch for changes to the psPolys: nTerm != nOrder.
     3192    psS32 nXterm = 1 + myPoly->nX;
     3193    psS32 nYterm = 1 + myPoly->nY;
     3194    psS32 nZterm = 1 + myPoly->nZ;
     3195    psS32 nTterm = 1 + myPoly->nZ;
     3196    nTerm = nXterm * nYterm * nZterm * nTterm;
     3197
     3198    A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64);
     3199    B = psVectorAlloc(nTerm, PS_TYPE_F64);
     3200
     3201    // Initialize data structures.
     3202    psVectorInit (B, 0.0);
     3203    psImageInit (A, 0.0);
     3204
     3205    // Sums look like: 1, x, x^2, ... x^(2n+1), y, xy, x^2y, ... x^(2n+1)*y, ...
     3206
     3207    // Build the B and A data structs.
     3208    for (int k  = 0; k < x->n; k++) {
     3209        if ((mask != NULL) && (mask->data.U8[k] & maskValue)) {
     3210            continue;
     3211        }
     3212
     3213        Sums = BuildSums4D(Sums, x->data.F64[k], y->data.F64[k], z->data.F64[k], t->data.F64[k], nXterm, nYterm, nZterm, nTterm);
     3214
     3215        if (fErr == NULL) {
     3216            wt = 1.0;
     3217        } else {
     3218            // this filters fErr == 0 values
     3219            wt = (fErr->data.F64[k] == 0.0) ? 0.0 : 1.0 / PS_SQR(fErr->data.F64[k]);
     3220        }
     3221
     3222        // we could skip half of the array and assign at the end
     3223        // we must handle masked orders
     3224        for (int ix = 0; ix < nXterm; ix++) {
     3225            for (int iy = 0; iy < nYterm; iy++) {
     3226                for (int iz = 0; iz < nZterm; iz++) {
     3227                    for (int it = 0; it < nTterm; it++) {
     3228                        if (myPoly->mask[ix][iy][iz][it])
     3229                            continue;
     3230                        int nx = ix+iy*nXterm+iz*nXterm*nYterm+it*nXterm*nYterm*nZterm;
     3231                        B->data.F64[nx] += f->data.F64[k] * Sums[ix][iy][iz][it] * wt;
     3232                    }
     3233                }
     3234            }
     3235        }
     3236
     3237        for (int ix = 0; ix < nXterm; ix++) {
     3238            for (int iy = 0; iy < nYterm; iy++) {
     3239                for (int iz = 0; iz < nZterm; iz++) {
     3240                    for (int it = 0; it < nTterm; it++) {
     3241                        if (myPoly->mask[ix][iy][iz][it])
     3242                            continue;
     3243                        int nx = ix+iy*nXterm+iz*nXterm*nYterm+it*nXterm*nYterm*nZterm;
     3244                        for (int jx = 0; jx < nXterm; jx++) {
     3245                            for (int jy = 0; jy < nYterm; jy++) {
     3246                                for (int jz = 0; jz < nZterm; jz++) {
     3247                                    for (int jt = 0; jt < nTterm; jt++) {
     3248                                        if (myPoly->mask[jx][jy][jz][jt])
     3249                                            continue;
     3250                                        int ny = jx+jy*nXterm+jz*nXterm*nYterm+jt*nXterm*nYterm*nZterm;
     3251                                        A->data.F64[nx][ny]+= Sums[ix+jx][iy+jy][iz+jz][it+jt] * wt;
     3252                                    }
     3253                                }
     3254                            }
     3255                        }
     3256                    }
     3257                }
     3258            }
     3259        }
     3260    }
     3261
     3262    for (int ix = 0; ix < nXterm; ix++) {
     3263        for (int iy = 0; iy < nYterm; iy++) {
     3264            for (int iz = 0; iz < nZterm; iz++) {
     3265                for (int it = 0; it < nTterm; it++) {
     3266                    if (!myPoly->mask[ix][iy][iz][it])
     3267                        continue;
     3268                    int nx = ix+iy*nXterm+iz*nXterm*nYterm+it*nXterm*nYterm*nZterm;
     3269                    B->data.F64[nx] = 0;
     3270                    for (int jx = 0; jx < nXterm; jx++) {
     3271                        for (int jy = 0; jy < nYterm; jy++) {
     3272                            for (int jz = 0; jz < nZterm; jz++) {
     3273                                for (int jt = 0; jt < nTterm; jt++) {
     3274                                    int ny = jx+jy*nXterm+jz*nXterm*nYterm+jt*nXterm*nYterm*nZterm;
     3275                                    A->data.F64[nx][ny] = (nx == ny) ? 1 : 0;
     3276                                }
     3277                            }
     3278                        }
     3279                    }
     3280                }
     3281            }
     3282        }
     3283    }
     3284
     3285    // does the solution in place
     3286
     3287    if (false == psGaussJordan(A, B)) {
     3288        psFree(A);
     3289        psFree(B);
     3290        for (int ix = 0; ix < 2*nXterm; ix++) {
     3291            for (int iy = 0; iy < 2*nYterm; iy++) {
     3292                for (int iz = 0; iz < 2*nZterm; iz++) {
     3293                    psFree(Sums[ix][iy][iz]);
     3294                }
     3295                psFree(Sums[ix][iy]);
     3296            }
     3297            psFree(Sums[ix]);
     3298        }
     3299        psFree(Sums);
     3300        psError(PS_ERR_UNKNOWN, false, "Failed to perform GaussJordan elimination.\n");
     3301        return(NULL);
     3302    }
     3303
     3304    // select the appropriate solution entries
     3305    for (int ix = 0; ix < nXterm; ix++) {
     3306        for (int iy = 0; iy < nYterm; iy++) {
     3307            for (int iz = 0; iz < nZterm; iz++) {
     3308                for (int it = 0; it < nTterm; it++) {
     3309                    int nx = ix+iy*nXterm+iz*nXterm*nYterm+it*nXterm*nYterm*nZterm;
     3310                    myPoly->coeff[ix][iy][iz][it] = B->data.F64[nx];
     3311                    myPoly->coeffErr[ix][iy][iz][it] = sqrt(A->data.F64[nx][nx]);
     3312                }
     3313            }
     3314        }
     3315    }
     3316
     3317    psFree(A);
     3318    psFree(B);
     3319
     3320    for (int ix = 0; ix < 2*nXterm; ix++) {
     3321        for (int iy = 0; iy < 2*nYterm; iy++) {
     3322            for (int iz = 0; iz < 2*nZterm; iz++) {
     3323                psFree(Sums[ix][iy][iz]);
     3324            }
     3325            psFree(Sums[ix][iy]);
     3326        }
     3327        psFree(Sums[ix]);
     3328    }
     3329    psFree(Sums);
     3330
     3331    psTrace(".psLib.dataManip.VectorFitPolynomial3DOrd", 4,
     3332            "---- VectorFitPolynomial3DOrd() begin ----\n");
     3333    return (myPoly);
    27963334}
    27973335
     
    30293567    }
    30303568
    3031     psLogMsg(__func__, PS_LOG_WARN, "WARNING: This function has not been implemented.  Returning NULL.\n");
    3032 
    3033     return(NULL);
     3569    // clipping range defined by min and max and/or clipSigma
     3570    float minClipSigma;
     3571    float maxClipSigma;
     3572    if (isfinite(stats->max)) {
     3573        maxClipSigma = fabs(stats->max);
     3574    } else {
     3575        maxClipSigma = fabs(stats->clipSigma);
     3576    }
     3577    if (isfinite(stats->min)) {
     3578        minClipSigma = fabs(stats->min);
     3579    } else {
     3580        minClipSigma = fabs(stats->clipSigma);
     3581    }
     3582    psVector *fit   = NULL;
     3583    psVector *resid = psVectorAlloc (x->n, PS_TYPE_F64);
     3584
     3585    // eventual expansion: user supplies one of various stats option pairs,
     3586    // eg (SAMPLE_MEAN | SAMPLE_STDEV) and the correct pair is used to
     3587    // evaluate the clipping sigma
     3588    // for now, for the SAMPLE_MEDIAN and SAMPLE_STDEV to be used
     3589    stats->options |= (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
     3590
     3591    for (int N = 0; N < stats->clipIter; N++) {
     3592        int Nkeep = 0;
     3593
     3594        poly = psVectorFitPolynomial4D (poly, mask, maskValue, f, fErr, x, y, z, t);
     3595        fit = psPolynomial4DEvalVector (poly, x, y, z, t);
     3596        resid = (psVector *) psBinaryOp (resid, (void *) f, "-", (void *) fit);
     3597
     3598        stats  = psVectorStats (stats, resid, NULL, mask, maskValue);
     3599        float minClipValue = -minClipSigma*stats->sampleStdev;
     3600        float maxClipValue = +maxClipSigma*stats->sampleStdev;
     3601        psTrace (".psphot.VectorClipFit", 5, "resid stats: %f +/- %f\n", stats->sampleMedian, stats->sampleStdev);
     3602        psTrace (".psphot.VectorClipFit", 5, "min clip: %f, max clip: %f\n", minClipValue, maxClipValue);
     3603
     3604        // set mask if pts are not valid
     3605        // we are masking out any point which is out of range
     3606        // recovery is not allowed with this scheme
     3607        for (int i = 0; i < resid->n; i++) {
     3608            if ((mask != NULL) && (mask->data.U8[i] & maskValue)) {
     3609                continue;
     3610            }
     3611            if (resid->data.F64[i] - stats->sampleMedian > maxClipValue) {
     3612                if (mask != NULL) {
     3613                    mask->data.U8[i] |= 0x01;
     3614                }
     3615                continue;
     3616            }
     3617            if (resid->data.F64[i] - stats->sampleMedian < minClipValue) {
     3618                if (mask != NULL) {
     3619                    mask->data.U8[i] |= 0x01;
     3620                }
     3621                continue;
     3622            }
     3623            Nkeep ++;
     3624        }
     3625
     3626        psTrace (".psphot.VectorClipFit", 4, "keeping %d of %d pts for fit\n",
     3627                 Nkeep, x->n);
     3628
     3629        psFree (fit);
     3630    }
     3631    // Free local temporary variables
     3632    psFree (resid);
     3633
     3634    if (poly == NULL) {
     3635        psError(PS_ERR_UNKNOWN, true, "Could not fit a polynomial to the data.  Returning NULL.\n");
     3636        return(NULL);
     3637    }
     3638    return(poly);
    30343639}
    3035 
    3036 
Note: See TracChangeset for help on using the changeset viewer.