IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 41896


Ignore:
Timestamp:
Nov 4, 2021, 6:10:51 PM (5 years ago)
Author:
eugene
Message:

merge changes from eam_branches/ipp-dev-20210817 (fix chebyshevs 1D, 2D, set DB field to NULL for inf, psFitsTableNew)

Location:
trunk/psLib
Files:
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/astro/psCoord.c

    r41531 r41896  
    4040#include "psMinimizePolyFit.h"
    4141
     42# define TEST_SAVE_INVERSE_TRANSFORM 0
     43
     44# if (TEST_SAVE_INVERSE_TRANSFORM)
     45# include "psBinaryOp.h"
     46# endif
     47
    4248# define ELIXIR_CODE 1
    4349
     
    8692    }
    8793
    88     psPlaneTransform *out = psPlaneTransformAlloc(1, 1);
     94    // since the output polynomial is 1st order, a Chebyshev is not really useful
     95    psPlaneTransform *out = psPlaneTransformAlloc(1, 1, PS_POLYNOMIAL_ORD);
    8996
    9097    psF64 r12 = 0.0;
     
    191198}
    192199
    193 psPlaneTransform* psPlaneTransformAlloc(int order1, int order2)
     200psPlaneTransform* psPlaneTransformAlloc(int order1, int order2, psPolynomialType type)
    194201{
    195202    PS_ASSERT_INT_NONNEGATIVE(order1, NULL);
     
    198205    psPlaneTransform *pt = psAlloc(sizeof(psPlaneTransform));
    199206
    200     pt->x = psPolynomial2DAlloc(PS_POLYNOMIAL_ORD, order1, order2);
    201     pt->y = psPolynomial2DAlloc(PS_POLYNOMIAL_ORD, order1, order2);
     207    pt->x = psPolynomial2DAlloc(type, order1, order2);
     208    pt->y = psPolynomial2DAlloc(type, order1, order2);
    202209
    203210    psMemSetDeallocator(pt, (psFreeFunc) planeTransformFree);
     
    797804    }
    798805
     806    // both polynomials in both input transforms must match type -- and for now be ORD
     807    psAssert (trans1->x->type == PS_POLYNOMIAL_ORD, "fix for CHEB");
     808    psAssert (trans1->y->type == PS_POLYNOMIAL_ORD, "fix for CHEB");
     809    psAssert (trans2->x->type == PS_POLYNOMIAL_ORD, "fix for CHEB");
     810    psAssert (trans2->y->type == PS_POLYNOMIAL_ORD, "fix for CHEB");
     811
    799812    //
    800813    // Determine the size of the new psPlaneTransform.
     
    814827    psPlaneTransform *myPT = NULL;
    815828    if (out == NULL) {
    816         myPT = psPlaneTransformAlloc(orderX, orderY);
     829        myPT = psPlaneTransformAlloc(orderX, orderY, PS_POLYNOMIAL_ORD);
    817830    } else {
    818831        if ((out->x->nX == orderX) &&
     
    834847        } else {
    835848            psFree(out);
    836             myPT = psPlaneTransformAlloc(orderX, orderY);
     849            myPT = psPlaneTransformAlloc(orderX, orderY, PS_POLYNOMIAL_ORD);
    837850        }
    838851    }
     
    10371050    psPlaneTransform *myPT = NULL;
    10381051    if (out == NULL) {
    1039         myPT = psPlaneTransformAlloc(order, order);
     1052      myPT = psPlaneTransformAlloc(order, order, PS_POLYNOMIAL_CHEB);
    10401053    } else {
    10411054      // the user has supplied a model with a specific order : fit that order
     
    10711084    result &= psVectorFitPolynomial2D(myPT->x, NULL, 0, xOut, NULL, xIn, yIn);
    10721085    result &= psVectorFitPolynomial2D(myPT->y, NULL, 0, yOut, NULL, xIn, yIn);
     1086
     1087# if (TEST_SAVE_INVERSE_TRANSFORM)
     1088
     1089    psVector *xFit = psPolynomial2DEvalVector (myPT->x, xIn, yIn);
     1090    psVector *xRes = (psVector *) psBinaryOp (NULL, xOut, "-", xFit);
     1091
     1092    psVector *yFit = psPolynomial2DEvalVector (myPT->y, xIn, yIn);
     1093    psVector *yRes = (psVector *) psBinaryOp (NULL, yOut, "-", yFit);
     1094
     1095    static int nOut = 0;
     1096    char filename[1024];
     1097    snprintf (filename, 1024, "test.fit.%03d.ply", nOut);
     1098    FILE *fp = fopen (filename, "w");
     1099   
     1100    fprintf (fp, " ---- xFit ---- \n");
     1101
     1102    for (int ix = 0; ix < myPT->x->nX + 1; ix++) {
     1103      for (int iy = 0; iy < myPT->x->nY + 1; iy++) {
     1104        fprintf (fp, "%18.12e ", myPT->x->coeff[ix][iy]);
     1105      }
     1106      fprintf (fp, "\n");
     1107    }
     1108    fprintf (fp, " ---- yFit ---- \n");
     1109
     1110    for (int ix = 0; ix < myPT->y->nX + 1; ix++) {
     1111      for (int iy = 0; iy < myPT->y->nY + 1; iy++) {
     1112        fprintf (fp, "%18.12e ", myPT->y->coeff[ix][iy]);
     1113      }
     1114      fprintf (fp, "\n");
     1115    }
     1116    fclose (fp);
     1117   
     1118    snprintf (filename, 1024, "test.fit.%03d.dat", nOut); nOut ++;
     1119    FILE *f1 = fopen (filename, "w");
     1120    for (int i = 0; i < xFit->n; i++) {
     1121      fprintf (f1, "%d : %f %f : %f %f : %f %f : %f %f\n", i,
     1122               xIn->data.F64[i], yIn->data.F64[i],
     1123               xOut->data.F64[i], yOut->data.F64[i],
     1124               xFit->data.F64[i], yFit->data.F64[i],
     1125               xRes->data.F64[i], yRes->data.F64[i]);
     1126    }
     1127    fclose (f1);
     1128
     1129    psStats *myStats = psStatsAlloc (PS_STAT_SAMPLE_STDEV);
     1130    psVectorStats (myStats, xRes, NULL, NULL, 0); float dX = myStats->sampleStdev;
     1131    psVectorStats (myStats, yRes, NULL, NULL, 0); float dY = myStats->sampleStdev;
     1132    fprintf (stderr, "xRes Sigma: %f  --  yRes Sigma %f\n", dX, dY);
     1133
     1134    psFree (myStats);
     1135    psFree (xFit);
     1136    psFree (yFit);
     1137    psFree (xRes);
     1138    psFree (yRes);
     1139
     1140# endif
    10731141
    10741142    psFree(inCoord);
  • trunk/psLib/src/astro/psCoord.h

    r41531 r41896  
    178178
    179179psPlaneTransform* psPlaneTransformAlloc(
    180     int order1,                        ///< The order of the x term in the transform.
    181     int order2                         ///< The order of the y term in the transform.
     180    int order1,                       ///< The order of the x term in the transform.
     181    int order2,                       ///< The order of the y term in the transform.
     182    psPolynomialType type             ///< The polynomial type (ORD or CHEB) for this transform
    182183) PS_ATTR_MALLOC;
    183184
  • trunk/psLib/src/db/psDB.c

    r40290 r41896  
    28752875
    28762876    switch (pType) {
    2877     case PS_DATA_S8:
     2877      case PS_DATA_S8:
    28782878        isNaN = PS_IS_NAN(psS8, data, PS_MAX_S8);
    28792879        break;
    2880     case PS_DATA_S16:
     2880      case PS_DATA_S16:
    28812881        isNaN = PS_IS_NAN(psS16, data, PS_MAX_S16);
    28822882        break;
    2883     case PS_DATA_S32:
     2883      case PS_DATA_S32:
    28842884        isNaN = PS_IS_NAN(psS32, data, PS_MAX_S32);
    28852885        break;
    2886     case PS_DATA_S64:
     2886      case PS_DATA_S64:
    28872887        isNaN = PS_IS_NAN(psS64, data, PS_MAX_S64);
    28882888        break;
    2889     case PS_DATA_U8:
     2889      case PS_DATA_U8:
    28902890        isNaN = PS_IS_NAN(psU8, data, PS_MAX_U8);
    28912891        break;
    2892     case PS_DATA_U16:
     2892      case PS_DATA_U16:
    28932893        isNaN = PS_IS_NAN(psU16, data, PS_MAX_U16);
    28942894        break;
    2895     case PS_DATA_U32:
     2895      case PS_DATA_U32:
    28962896        isNaN = PS_IS_NAN(psU32, data, PS_MAX_U32);
    28972897        break;
    2898     case PS_DATA_U64:
     2898      case PS_DATA_U64:
    28992899        isNaN = PS_IS_NAN(psU64, data, PS_MAX_U64);
    29002900        break;
    2901     case PS_DATA_F32:
    2902       isNaN = isnan(*((psF32 *) data));
    2903       break;
    2904     case PS_DATA_F64:
    2905       isNaN = isnan(*((psF64 *) data));
    2906       break;
    2907     case PS_DATA_BOOL:
    2908         // XXX: what is NaN for a bool?
    2909         isNaN = PS_IS_NAN(psU8, data, PS_MAX_U8);
     2901      case PS_DATA_F32:
     2902        isNaN = !isfinite(*((psF32 *) data)); // trap nan, +inf, -inf
     2903        break;
     2904      case PS_DATA_F64:
     2905        isNaN = !isfinite(*((psF64 *) data)); // trap nan, +inf, -inf
     2906        break;
     2907      case PS_DATA_BOOL:
     2908        isNaN = PS_IS_NAN(psU8, data, PS_MAX_U8); // probably meaningless
    29102909        break;
    29112910    }
  • trunk/psLib/src/fits/psFitsTableNew.c

    r33030 r41896  
    137137
    138138    return table;
     139}
     140
     141psFitsTable *psFitsTableCreate (psArray *tableColumns, int numRows) {
     142
     143    psFitsTable *table = psFitsTableAlloc (tableColumns->n, numRows);
     144
     145    // now define the table colums
     146    for (int i = 0; i < tableColumns->n; i++) {
     147        psFitsTableColumn *column = &table->columns[i];
     148
     149        psFitsTableColumn *myColumn = tableColumns->data[i];
     150
     151        column->name = psStringCopy (myColumn->name);
     152        column->type = myColumn->type;
     153        column->vectorType = myColumn->vectorType;
     154        column->elementSize = myColumn->elementSize;
     155       
     156        psMetadataAddS32(table->index, PS_LIST_TAIL, column->name, 0, NULL, i);
     157
     158        switch (column->type) {
     159          case PS_DATA_S8:  column->data.S8  = psAlloc(sizeof(psS8) *table->numRows); break;
     160          case PS_DATA_S16: column->data.S16 = psAlloc(sizeof(psS16)*table->numRows); break;
     161          case PS_DATA_S32: column->data.S32 = psAlloc(sizeof(psS32)*table->numRows); break;
     162          case PS_DATA_S64: column->data.S64 = psAlloc(sizeof(psS64)*table->numRows); break;
     163          case PS_DATA_U8:  column->data.U8  = psAlloc(sizeof(psU8) *table->numRows); break;
     164          case PS_DATA_U16: column->data.U16 = psAlloc(sizeof(psU16)*table->numRows); break;
     165          case PS_DATA_U32: column->data.U32 = psAlloc(sizeof(psU32)*table->numRows); break;
     166          case PS_DATA_U64: column->data.U64 = psAlloc(sizeof(psU64)*table->numRows); break;
     167          case PS_DATA_F32: column->data.F32 = psAlloc(sizeof(psF32)*table->numRows); break;
     168          case PS_DATA_F64: column->data.F64 = psAlloc(sizeof(psF64)*table->numRows); break;
     169          default: break;
     170        }
     171    }
     172    return table;
     173}
     174
     175static void freeColumn(psFitsTableColumn *column)
     176{
     177    // add any element frees here
     178    return;
     179}
     180
     181psFitsTableColumn *psFitsTableColumnAlloc (char *name, psDataType type) {
     182
     183    psFitsTableColumn *column = psAlloc(sizeof(psFitsTableColumn));
     184    psMemSetDeallocator(column, (psFreeFunc) freeColumn);
     185
     186    column->name = psStringCopy (name);
     187    column->type = type;
     188    column->vectorType  = 0;
     189    column->elementSize = 1;
     190    column->data.S8 = NULL; // no data yet allocated, place-holder only
     191    return column;
     192}
     193
     194bool psFitsTableColumnAdd (psArray *tableColumns, char *name, psDataType type) {
     195    psFitsTableColumn *column = psFitsTableColumnAlloc (name, type);
     196    psArrayAdd (tableColumns, 10, column);
     197    return true;
    139198}
    140199
     
    397456psFitsTableGetNumTYPE(Bool, BOOL);
    398457
     458#define psFitsTableSetNumTYPE(TYPE, NAME) \
     459    bool psFitsTableSet##NAME(psFitsTable *table, int row, const char *name, ps##TYPE value) { \
     460                                                                        \
     461    if (row >= table->numRows || row < 0) { return false; }             \
     462                                                                        \
     463    bool mdok;                                                          \
     464    int col = psMetadataLookupS32(&mdok, table->index, name);           \
     465    if (!mdok) { return false; }                                        \
     466    if (col < 0) { return false; }                                      \
     467                                                                        \
     468    psFitsTableColumn *column = &table->columns[col];                   \
     469    switch (column->type) {                                             \
     470      case PS_DATA_S8:                                                  \
     471        column->data.S8[row] = (psS8) value;                            \
     472        break;                                                          \
     473      case PS_DATA_S16:                                                 \
     474        column->data.S16[row] = (psS16) value;                          \
     475        break;                                                          \
     476      case PS_DATA_S32:                                                 \
     477        column->data.S32[row] = (psS32) value;                          \
     478        break;                                                          \
     479      case PS_DATA_S64:                                                 \
     480        column->data.S64[row] = (psS64) value;                          \
     481        break;                                                          \
     482      case PS_DATA_U8:                                                  \
     483        column->data.U8[row] = (psU8) value;                            \
     484        break;                                                          \
     485      case PS_DATA_U16:                                                 \
     486        column->data.U16[row] = (psU16) value;                          \
     487        break;                                                          \
     488      case PS_DATA_U32:                                                 \
     489        column->data.U32[row] = (psU32) value;                          \
     490        break;                                                          \
     491      case PS_DATA_U64:                                                 \
     492        column->data.U64[row] = (psU64) value;                          \
     493        break;                                                          \
     494      case PS_DATA_F32:                                                 \
     495        column->data.F32[row] = (psF32) value;                          \
     496        break;                                                          \
     497      case PS_DATA_F64:                                                 \
     498        column->data.F64[row] = (psF64) value;                          \
     499        break;                                                          \
     500      case PS_DATA_BOOL:                                                \
     501        if (value) { column->data.F64[row] = 1; }                       \
     502        else { column->data.F64[row] = 0; }                             \
     503        break;                                                          \
     504      default:                                                          \
     505        /* if you get to this point, the value is not a number. */      \
     506        return false;                                                   \
     507        break;                                                          \
     508    }                                                                   \
     509    return true;                                                        \
     510}
     511
     512psFitsTableSetNumTYPE(S8, S8);
     513psFitsTableSetNumTYPE(U8, U8);
     514psFitsTableSetNumTYPE(S16, S16);
     515psFitsTableSetNumTYPE(U16, U16);
     516psFitsTableSetNumTYPE(S32, S32);
     517psFitsTableSetNumTYPE(U32, U32);
     518psFitsTableSetNumTYPE(S64, S64);
     519psFitsTableSetNumTYPE(U64, U64);
     520psFitsTableSetNumTYPE(F32, F32);
     521psFitsTableSetNumTYPE(F64, F64);
     522psFitsTableSetNumTYPE(Bool, BOOL);
     523
    399524// remove rows from table that are marked in the mask array as censored.
    400525bool psFitsTableCensor(psFitsTable *table, bool *censorMask)
  • trunk/psLib/src/fits/psFitsTableNew.h

    r32263 r41896  
    5555// Get value for given row and column name
    5656psBool psFitsTableGetBool(bool *status, psFitsTable *table, int row, const char* name);
    57 psS8 psFitsTableGetS8(bool *status, psFitsTable *table, int row, const char* name);
    58 psU8 psFitsTableGetU8(bool *status, psFitsTable *table, int row, const char* name);
     57psS8  psFitsTableGetS8(bool *status, psFitsTable *table, int row, const char* name);
     58psU8  psFitsTableGetU8(bool *status, psFitsTable *table, int row, const char* name);
    5959psS16 psFitsTableGetS16(bool *status, psFitsTable *table, int row, const char* name);
    6060psU16 psFitsTableGetU16(bool *status, psFitsTable *table, int row, const char* name);
     
    6363psS64 psFitsTableGetS64(bool *status, psFitsTable *table, int row, const char* name);
    6464psU64 psFitsTableGetU64(bool *status, psFitsTable *table, int row, const char* name);
    65 
    6665psF32 psFitsTableGetF32(bool *status, psFitsTable *table, int row, const char* name);
    6766psF64 psFitsTableGetF64(bool *status, psFitsTable *table, int row, const char* name);
    6867
     68psFitsTable *psFitsTableCreate (psArray *tableColumns, int numRows);
     69bool psFitsTableColumnAdd (psArray *tableColumns, char *name, psDataType type);
     70psFitsTableColumn *psFitsTableColumnAlloc (char *name, psDataType type);
     71
     72bool psFitsTableSetS8 (psFitsTable *table, int row, const char* name, psS8  value);
     73bool psFitsTableSetU8 (psFitsTable *table, int row, const char* name, psU8  value);
     74bool psFitsTableSetS16(psFitsTable *table, int row, const char* name, psS16 value);
     75bool psFitsTableSetU16(psFitsTable *table, int row, const char* name, psU16 value);
     76bool psFitsTableSetS32(psFitsTable *table, int row, const char* name, psS32 value);
     77bool psFitsTableSetU32(psFitsTable *table, int row, const char* name, psU32 value);
     78bool psFitsTableSetS64(psFitsTable *table, int row, const char* name, psS64 value);
     79bool psFitsTableSetU64(psFitsTable *table, int row, const char* name, psU64 value);
     80bool psFitsTableSetF32(psFitsTable *table, int row, const char* name, psF32 value);
     81bool psFitsTableSetF64(psFitsTable *table, int row, const char* name, psF64 value);
     82
    6983#endif
  • trunk/psLib/src/math/psMinimizePolyFit.c

    r41532 r41896  
    3535
    3636#include "psMinimizePolyFit.h"
     37#include "psAbort.h"
    3738#include "psAssert.h"
    3839#include "psMinimizeLMM.h"  // For Gauss-Jordan routines
     
    12251226
    12261227/******************************************************************************
     1228VectorFitPolynomial2DCheb(myPoly, *mask, maskValue, *f, *fErr, *x, *y): This is
     1229a private routine which will fit a 2-D polynomial to a set of (x, y)-(f)
     1230pairs.  All non-NULL vectors must be of type PS_TYPE_F64.
     1231 
     1232 *****************************************************************************/
     1233static bool VectorFitPolynomial2DCheb(
     1234    psPolynomial2D* myPoly,
     1235    const psVector *f,
     1236    const psVector *x,
     1237    const psVector *y)
     1238{
     1239    psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__);
     1240    PS_ASSERT_POLY_NON_NULL(myPoly, false);
     1241    PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, false);
     1242    PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, false);
     1243    PS_ASSERT_VECTOR_NON_NULL(f, false);
     1244    PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, false);
     1245    PS_ASSERT_VECTOR_NON_NULL(x, false);
     1246    PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, false);
     1247    PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);
     1248    PS_ASSERT_VECTOR_NON_NULL(y, false);
     1249    PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, false);
     1250    PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);
     1251
     1252    // Number of polynomial terms
     1253    int nXterm = 1 + myPoly->nX;      // Number of terms in x
     1254    int nYterm = 1 + myPoly->nY;      // Number of terms in y
     1255    int nTerm = nXterm * nYterm;      // Total number of terms
     1256    if (nXterm > 9) {
     1257        psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit: orders higher than 9 are not yet coded\n");
     1258        return false;
     1259    }
     1260    if (nYterm > 9) {
     1261        psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit: orders higher than 9 are not yet coded\n");
     1262        return false;
     1263    }
     1264
     1265    // determine scale factors
     1266    if (!psChebyshevSetScale (myPoly, x, 0)) { psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit.\n"); return false; }
     1267    if (!psChebyshevSetScale (myPoly, y, 1)) { psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit.\n"); return false; }
     1268
     1269    // generate normalized vectors
     1270    psVector *xNorm = psChebyshevNormVector (myPoly, x, 0);
     1271    psVector *yNorm = psChebyshevNormVector (myPoly, y, 1);
     1272
     1273    // generate the N cheb polynomials based on xNorm, yNorm
     1274    psArray *xPolySet = psArrayAlloc (nXterm);
     1275    for (int i = 0; i < nXterm; i++) {
     1276        xPolySet->data[i] = psChebyshevPolyVector (xNorm, i);
     1277    }
     1278    psArray *yPolySet = psArrayAlloc (nYterm);
     1279    for (int i = 0; i < nYterm; i++) {
     1280        yPolySet->data[i] = psChebyshevPolyVector (yNorm, i);
     1281    }
     1282
     1283    psF64 *fData = f->data.F64;         // Dereference f
     1284
     1285    psImage *A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64); // Least-squares matrix
     1286    psVector *B = psVectorAlloc(nTerm, PS_TYPE_F64); // Least-squares vector
     1287
     1288    // Initialize data structures (should not be able to fail)
     1289    psAssert (psImageInit(A, 0.0), "Could initialize data structures A");
     1290    psAssert (psVectorInit(B, 0.0), "Could initialize data structures B");
     1291
     1292    // Dereference stuff, to make the loop go faster
     1293    psF64 **matrix = A->data.F64;       // Dereference the least-squares matrix
     1294    psF64 *vector = B->data.F64;        // Dereference the least-squares vector
     1295
     1296    // loop over all elements of the data vector
     1297    for (int k = 0; k < x->n; k++) {
     1298
     1299        if (!finite(fData[k])) continue;
     1300   
     1301        // XXX can we only calculate the upper diagonal?
     1302        int nelem = 0;
     1303        for (int jx = 0; jx < nXterm; jx++) {
     1304            psVector *jxCheb = xPolySet->data[jx];
     1305            for (int jy = 0; jy < nYterm; jy++) {
     1306                psVector *jyCheb = yPolySet->data[jy];
     1307                psF64 chebValue = jxCheb->data.F64[k] * jyCheb->data.F64[k];
     1308               
     1309                vector[nelem] += fData[k] * chebValue;
     1310
     1311                int melem = 0;
     1312                for (int kx = 0; kx < nXterm; kx++) {
     1313                    psVector *kxCheb = xPolySet->data[kx];
     1314                    for (int ky = 0; ky < nYterm; ky++) {
     1315                        psVector *kyCheb = yPolySet->data[ky];
     1316                        matrix[nelem][melem] += chebValue * kxCheb->data.F64[k]*kyCheb->data.F64[k];
     1317                        melem++;
     1318                    }
     1319                }
     1320                nelem++;
     1321            }
     1322        }
     1323    }
     1324
     1325    if (psTraceGetLevel("psLib.math") >= 4) {
     1326        printf("Least-squares vector:\n");
     1327        for (int i = 0; i < nTerm; i++) {
     1328            printf("%f ", B->data.F64[i]);
     1329        }
     1330        printf("\n");
     1331        printf("Least-squares matrix:\n");
     1332        for (int i = 0; i < nTerm; i++) {
     1333            for (int j = 0; j < nTerm; j++) {
     1334                printf("%f ", A->data.F64[i][j]);
     1335            }
     1336            printf("\n");
     1337        }
     1338    }
     1339
     1340    bool status = false;
     1341    if (USE_GAUSS_JORDAN) {
     1342        status = psMatrixGJSolve(A, B);
     1343    } else {
     1344        status = psMatrixLUSolve(A, B);
     1345    }
     1346    if (!status) {
     1347        psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n");
     1348        goto escape;
     1349    }
     1350
     1351    // unroll the result:
     1352    int nelem = 0;
     1353    for (int jx = 0; jx < nXterm; jx++) {
     1354        for (int jy = 0; jy < nYterm; jy++) {
     1355            myPoly->coeff[jx][jy]    = B->data.F64[nelem];
     1356            myPoly->coeffErr[jx][jy] = sqrt(A->data.F64[nelem][nelem]);
     1357            nelem ++;
     1358        }
     1359    }
     1360    psFree(A);
     1361    psFree(B);
     1362
     1363    psFree (xNorm);
     1364    psFree (yNorm);
     1365    psFree (xPolySet);
     1366    psFree (yPolySet);
     1367
     1368    return true;
     1369
     1370escape:
     1371    psFree (A);
     1372    psFree (B);
     1373    return false;
     1374}
     1375
     1376/******************************************************************************
    12271377psVectorFitPolynomial2D():  This routine fits a 2D polynomial of arbitrary
    12281378degree (specified in poly) to the data points (x, y)-(f) and returns that
     
    12401390{
    12411391    PS_ASSERT_POLY_NON_NULL(poly, false);
    1242     PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false);
     1392    // PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false);
    12431393
    12441394    PS_ASSERT_VECTOR_NON_NULL(f, false);
     
    12771427        break;
    12781428    case PS_POLYNOMIAL_CHEB:
    1279         if (mask != NULL) {
    1280             psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring mask and maskValue with Chebyshev polynomials.\n");
    1281         }
    1282         psError(PS_ERR_UNKNOWN, true, "2-D Chebyshev polynomial vector fitting has not been implemented.  Returning NULL.\n");
    1283         result = false;
    1284         break;
     1429      if (mask != NULL) {
     1430          psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring mask and maskValue with Chebyshev polynomials.\n");
     1431      }
     1432      if (fErr != NULL) {
     1433          psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring error values for Chebyshev polynomials.\n");
     1434      }
     1435      result = VectorFitPolynomial2DCheb(poly, f64, x64, y64);
     1436      if (!result) {
     1437          psError(PS_ERR_UNKNOWN, true, "Could not fit polynomial.  Returning NULL.\n");
     1438      }
     1439      break;
    12851440    default:
    12861441        psError(PS_ERR_UNKNOWN, true, "Incorrect polynomial type.  Returning NULL.\n");
  • trunk/psLib/src/math/psPolynomial.c

    r15253 r41896  
    3636#include "psLogMsg.h"
    3737#include "psPolynomial.h"
     38#include "psAbort.h"
    3839#include "psAssert.h"
    3940
     
    203204
    204205
     206/** This function calculates the appropriate scaling factors needed to normalize the
     207 * input vector to the range -1 : +1.  These are stored on the polynomial in the given
     208 * direction.
     209 */
     210bool psChebyshevSetScale (psPolynomial2D* myPoly, const psVector *vec, int dir) {
     211
     212    psAssert ((dir == 0) || (dir == 1), "invalid direction %d\n", dir);
     213
     214    // find the min and max of the vector
     215    psF64 minValue = NAN;
     216    psF64 maxValue = NAN;
     217
     218    for (int i = 0; i < vec->n; i++) {
     219        if (isnan(vec->data.F64[i])) continue;
     220        if (isnan(minValue)) { minValue = vec->data.F64[i]; }
     221        if (isnan(maxValue)) { maxValue = vec->data.F64[i]; }
     222        minValue = PS_MIN(minValue, vec->data.F64[i]);
     223        maxValue = PS_MAX(maxValue, vec->data.F64[i]);
     224    }
     225    if (minValue == maxValue) {
     226        psWarning ("insufficient data range to determine scale factors\n");
     227        return false;
     228    }
     229
     230    myPoly->scale[dir] = 2.0 / (maxValue - minValue);
     231    myPoly->zero[dir]  = 1 - myPoly->scale[dir] * maxValue;
     232    return true;
     233}
     234
     235/** This function generates a normalized vector in the range -1 : +1 based on the input
     236    vector using the scale factors stored in myPoly in the given direction.
     237 */
     238psVector *psChebyshevNormVector (const psPolynomial2D* myPoly, const psVector *vec, int dir) {
     239
     240    psVector *norm = psVectorAlloc (vec->n, PS_TYPE_F64);
     241
     242    if (vec->type.type == PS_TYPE_F64) {
     243        for (int i = 0; i < vec->n; i++) {
     244            norm->data.F64[i] = vec->data.F64[i]*myPoly->scale[dir] + myPoly->zero[dir];
     245        }
     246        return norm;
     247    }
     248    if (vec->type.type == PS_TYPE_F32) {
     249        for (int i = 0; i < vec->n; i++) {
     250            norm->data.F64[i] = vec->data.F32[i]*myPoly->scale[dir] + myPoly->zero[dir];
     251        }
     252        return norm;
     253    }
     254
     255    psError(PS_ERR_UNKNOWN, true, "invalid type for chebyshev polynomial");
     256    return NULL;
     257}
     258
     259# define CHEB_EVAL_0(OUT,IN) {OUT = 1.0;}
     260# define CHEB_EVAL_1(OUT,IN) {                       OUT = IN; }
     261# define CHEB_EVAL_2(OUT,IN) {psF64 X2 = PS_SQR(IN); OUT = 2.0*X2 - 1.0; }
     262# define CHEB_EVAL_3(OUT,IN) {psF64 X2 = PS_SQR(IN); OUT = IN*(4.0*X2 - 3.0); }
     263# define CHEB_EVAL_4(OUT,IN) {psF64 X2 = PS_SQR(IN); OUT = X2*(8.0*X2 - 8.0) + 1.0; }
     264# define CHEB_EVAL_5(OUT,IN) {psF64 X2 = PS_SQR(IN); OUT = IN *(X2*(16.0*X2 - 20.0) + 5.0); }
     265# define CHEB_EVAL_6(OUT,IN) {psF64 X2 = PS_SQR(IN); OUT = X2*(X2*(32.0*X2 - 48.0) + 18.0) - 1.0; }
     266# define CHEB_EVAL_7(OUT,IN) {psF64 X2 = PS_SQR(IN); OUT = IN *(X2*(X2*(64.0*X2 - 112.0) + 56.0) - 7.0); }
     267# define CHEB_EVAL_8(OUT,IN) {psF64 X2 = PS_SQR(IN); OUT = X2*(X2*(X2*(128.0*X2 - 256.0) + 160.0) - 32.0) + 1.0; }
     268# define CHEB_EVAL_9(OUT,IN) {psF64 X2 = PS_SQR(IN); OUT = IN *(X2*(X2*(X2*(256.0*X2 - 576.0) + 432.0) - 129.0) + 9.0); }
     269
     270/** This function generates a vector containing the values of a Chebyshev polynomial of
     271    the given order evaluated at the coordinates given by the input vector, i.e., this
     272    function returns the vector T^n (x_i) where x_i is the input vector of values and n is
     273    the polynomial order.
     274 */
     275psVector *psChebyshevPolyVector (const psVector *vec, int order) {
     276
     277    if (order > 9) {
     278        psWarning ("Chebyshev orders higher than 9 are not yet coded\n");
     279        return NULL;
     280    }
     281
     282    psVector *out = psVectorAlloc (vec->n, PS_TYPE_F64);
     283
     284    // easy but non-general implementation
     285    switch (order) {
     286      case 0:
     287        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_0(out->data.F64[i], vec->data.F64[i]); } break;
     288      case 1:
     289        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_1(out->data.F64[i], vec->data.F64[i]); } break;
     290      case 2:
     291        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_2(out->data.F64[i], vec->data.F64[i]); } break;
     292      case 3:
     293        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_3(out->data.F64[i], vec->data.F64[i]); } break;
     294      case 4:
     295        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_4(out->data.F64[i], vec->data.F64[i]); } break;
     296      case 5:
     297        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_5(out->data.F64[i], vec->data.F64[i]); } break;
     298      case 6:
     299        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_6(out->data.F64[i], vec->data.F64[i]); } break;
     300      case 7:
     301        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_7(out->data.F64[i], vec->data.F64[i]); } break;
     302      case 8:
     303        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_8(out->data.F64[i], vec->data.F64[i]); } break;
     304      case 9:
     305        for (int i = 0; i < vec->n; i++) { CHEB_EVAL_9(out->data.F64[i], vec->data.F64[i]); } break;
     306      default:
     307        psWarning ("Chebyshev orders higher than 9 are not yet coded\n");
     308        psFree (out);
     309        return NULL;
     310    }
     311
     312    return out;
     313}
     314
    205315/*****************************************************************************
    206316    Polynomial coefficients will be accessed in [w][x][y][z] fashion.
     
    233343}
    234344
    235 // XXX: You can do this without having to psAlloc() vector d.
    236 // XXX: How does the mask vector effect Crenshaw's formula?
    237 // NOTE: We assume that x is scaled between -1.0 and 1.0;
    238 // XXX: Create a faster version for low-order Chebyshevs.
    239 static psF64 chebPolynomial1DEval(
    240     psF64 x,
    241     const psPolynomial1D* poly)
    242 {
    243     PS_ASSERT_DOUBLE_WITHIN_RANGE(x, -1.0, 1.0, NAN);
     345static psF64 chebPolynomial1DEval(psF64 x, const psPolynomial1D* poly) {
     346
    244347    PS_ASSERT_INT_LARGER_THAN_OR_EQUAL(poly->nX, 0, NAN);
     348
     349    psF64 xNorm = x*poly->scale[0] + poly->zero[0];
     350
     351    psF64 polySum = 0.0;
     352
     353    for (int ix = 0; ix <= poly->nX; ix++) {
     354        if (poly->coeffMask[ix] & PS_POLY_MASK_SET) continue;
     355        psF64 xCheb = NAN;
     356        switch (ix) {
     357          case 0: CHEB_EVAL_0 (xCheb, xNorm); break;
     358          case 1: CHEB_EVAL_1 (xCheb, xNorm); break;
     359          case 2: CHEB_EVAL_2 (xCheb, xNorm); break;
     360          case 3: CHEB_EVAL_3 (xCheb, xNorm); break;
     361          case 4: CHEB_EVAL_4 (xCheb, xNorm); break;
     362          case 5: CHEB_EVAL_5 (xCheb, xNorm); break;
     363          case 6: CHEB_EVAL_6 (xCheb, xNorm); break;
     364          case 7: CHEB_EVAL_7 (xCheb, xNorm); break;
     365          case 8: CHEB_EVAL_8 (xCheb, xNorm); break;
     366          case 9: CHEB_EVAL_9 (xCheb, xNorm); break;
     367          default:
     368            break;
     369        }
     370        polySum += poly->coeff[ix] * xCheb;
     371    }
     372    return polySum;
     373}
     374
     375/*** version 1 is a general case and could be used for Norder > 9.  ***/
     376# ifdef CHEB_VERSION_1
     377void oldcode_1(void) {
    245378    psVector *d;
     379    psF64 tmp = 0.0;
    246380
    247381    unsigned int nTerms = 1 + poly->nX;
    248382    unsigned int i;
    249     psF64 tmp = 0.0;
    250383
    251384    // Special case where the Chebyshev poly is constant.
     
    268401    }
    269402
    270     if (1) {
    271         // General case where the Chebyshev poly has 2 or more terms.
    272         d = psVectorAlloc(nTerms, PS_TYPE_F64);
    273         if (!(poly->coeffMask[nTerms-1] & PS_POLY_MASK_SET)) {
    274             d->data.F64[nTerms-1] = poly->coeff[nTerms-1];
    275         } else {
    276             d->data.F64[nTerms-1] = 0.0;
    277         }
    278 
    279         d->data.F64[nTerms-2] = (2.0 * x * d->data.F64[nTerms-1]);
    280         if (!(poly->coeffMask[nTerms-2] & PS_POLY_MASK_SET)) {
    281             d->data.F64[nTerms-2] += poly->coeff[nTerms-2];
    282         }
    283 
    284         for (i=nTerms-3;i>=1;i--) {
    285             d->data.F64[i] = (2.0 * x * d->data.F64[i+1]) - (d->data.F64[i+2]);
    286             if (!(poly->coeffMask[i] & PS_POLY_MASK_SET)) {
    287                 d->data.F64[i] += poly->coeff[i];
    288             }
    289         }
    290 
    291         tmp = (x * d->data.F64[1]) - (d->data.F64[2]);
    292         if (!(poly->coeffMask[0] & PS_POLY_MASK_SET)) {
    293             tmp += (0.5 * poly->coeff[0]);
    294         }
    295         psFree(d);
     403    // General case where the Chebyshev poly has 2 or more terms.
     404    d = psVectorAlloc(nTerms, PS_TYPE_F64);
     405    if (!(poly->coeffMask[nTerms-1] & PS_POLY_MASK_SET)) {
     406        d->data.F64[nTerms-1] = poly->coeff[nTerms-1];
    296407    } else {
    297         // XXX: This is old code that does not use Clenshaw's formula.  Get rid of it.
    298         psPolynomial1D **chebPolys = p_psCreateChebyshevPolys(1 + poly->nX);
    299 
    300         tmp = 0.0;
    301         for (psS32 i=0;i<(1 + poly->nX);i++) {
    302             tmp+= (poly->coeff[i] * psPolynomial1DEval(chebPolys[i], x));
    303         }
    304         tmp-= (poly->coeff[0]/2.0);
    305 
    306         for (psS32 i=0;i<(1 + poly->nX);i++) {
    307             psFree(chebPolys[i]);
    308         }
    309         psFree(chebPolys);
    310     }
     408        d->data.F64[nTerms-1] = 0.0;
     409    }
     410
     411    d->data.F64[nTerms-2] = (2.0 * x * d->data.F64[nTerms-1]);
     412    if (!(poly->coeffMask[nTerms-2] & PS_POLY_MASK_SET)) {
     413        d->data.F64[nTerms-2] += poly->coeff[nTerms-2];
     414    }
     415
     416    for (i=nTerms-3;i>=1;i--) {
     417        d->data.F64[i] = (2.0 * x * d->data.F64[i+1]) - (d->data.F64[i+2]);
     418        if (!(poly->coeffMask[i] & PS_POLY_MASK_SET)) {
     419            d->data.F64[i] += poly->coeff[i];
     420        }
     421    }
     422
     423    tmp = (x * d->data.F64[1]) - (d->data.F64[2]);
     424    if (!(poly->coeffMask[0] & PS_POLY_MASK_SET)) {
     425        tmp += (0.5 * poly->coeff[0]);
     426    }
     427    psFree(d);
     428}
     429# endif
     430
     431/*** version 0 should be removed when version 2 is ready ***/
     432# ifdef CHEB_VERSION_0
     433void oldcode_0(void) {
     434    // XXX: This is old code that does not use Clenshaw's formula.  Get rid of it.
     435    psPolynomial1D **chebPolys = p_psCreateChebyshevPolys(1 + poly->nX);
     436
     437    tmp = 0.0;
     438    for (psS32 i=0;i<(1 + poly->nX);i++) {
     439        tmp+= (poly->coeff[i] * psPolynomial1DEval(chebPolys[i], x));
     440    }
     441    tmp-= (poly->coeff[0]/2.0);
     442
     443    for (psS32 i=0;i<(1 + poly->nX);i++) {
     444        psFree(chebPolys[i]);
     445    }
     446    psFree(chebPolys);
    311447
    312448    return(tmp);
    313449}
     450# endif
    314451
    315452static psF64 ordPolynomial2DEval(psF64 x,
     
    343480                                  const psPolynomial2D* poly)
    344481{
    345     PS_ASSERT_DOUBLE_WITHIN_RANGE(x, -1.0, 1.0, 0.0);
    346     PS_ASSERT_DOUBLE_WITHIN_RANGE(y, -1.0, 1.0, 0.0);
    347482    PS_ASSERT_POLY_NON_NULL(poly, NAN);
    348483
    349     unsigned int loop_x = 0;
    350     unsigned int loop_y = 0;
    351     unsigned int i = 0;
     484    psF64 xNorm = x*poly->scale[0] + poly->zero[0];
     485    psF64 yNorm = y*poly->scale[1] + poly->zero[1];
     486
    352487    psF64 polySum = 0.0;
    353     psPolynomial1D* *chebPolys = NULL;
    354     unsigned int maxChebyPoly = 0;
    355 
    356     // Determine how many Chebyshev polynomials
    357     // are needed, then create them.
    358     maxChebyPoly = poly->nX;
    359     if (poly->nY > maxChebyPoly) {
    360         maxChebyPoly = poly->nY;
    361     }
    362     chebPolys = p_psCreateChebyshevPolys(maxChebyPoly + 1);
    363 
    364     for (loop_x = 0; loop_x < (1 + poly->nX); loop_x++) {
    365         for (loop_y = 0; loop_y < (1 + poly->nY); loop_y++) {
    366             if (!(poly->coeffMask[loop_x][loop_y] & PS_POLY_MASK_SET)) {
    367                 polySum += poly->coeff[loop_x][loop_y] *
    368                            psPolynomial1DEval(chebPolys[loop_x], x) *
    369                            psPolynomial1DEval(chebPolys[loop_y], y);
    370             }
    371         }
    372     }
    373     for (i=0;i<maxChebyPoly+1;i++) {
    374         psFree(chebPolys[i]);
    375     }
    376     psFree(chebPolys);
     488
     489    // XXX this could be quicker if we saved the N xvalues are re-used the resuls
     490    for (int ix = 0; ix <= poly->nX; ix++) {
     491        psF64 xCheb = NAN;
     492        switch (ix) {
     493          case 0: CHEB_EVAL_0 (xCheb, xNorm); break;
     494          case 1: CHEB_EVAL_1 (xCheb, xNorm); break;
     495          case 2: CHEB_EVAL_2 (xCheb, xNorm); break;
     496          case 3: CHEB_EVAL_3 (xCheb, xNorm); break;
     497          case 4: CHEB_EVAL_4 (xCheb, xNorm); break;
     498          case 5: CHEB_EVAL_5 (xCheb, xNorm); break;
     499          case 6: CHEB_EVAL_6 (xCheb, xNorm); break;
     500          case 7: CHEB_EVAL_7 (xCheb, xNorm); break;
     501          case 8: CHEB_EVAL_8 (xCheb, xNorm); break;
     502          case 9: CHEB_EVAL_9 (xCheb, xNorm); break;
     503          default:
     504            break;
     505        }
     506        for (int iy = 0; iy <= poly->nY; iy++) {
     507            if (poly->coeffMask[ix][iy] & PS_POLY_MASK_SET) continue;
     508            psF64 yCheb = NAN;
     509            switch (iy) {
     510              case 0: CHEB_EVAL_0 (yCheb, yNorm); break;
     511              case 1: CHEB_EVAL_1 (yCheb, yNorm); break;
     512              case 2: CHEB_EVAL_2 (yCheb, yNorm); break;
     513              case 3: CHEB_EVAL_3 (yCheb, yNorm); break;
     514              case 4: CHEB_EVAL_4 (yCheb, yNorm); break;
     515              case 5: CHEB_EVAL_5 (yCheb, yNorm); break;
     516              case 6: CHEB_EVAL_6 (yCheb, yNorm); break;
     517              case 7: CHEB_EVAL_7 (yCheb, yNorm); break;
     518              case 8: CHEB_EVAL_8 (yCheb, yNorm); break;
     519              case 9: CHEB_EVAL_9 (yCheb, yNorm); break;
     520              default:
     521                break;
     522            }
     523            polySum += poly->coeff[ix][iy] * xCheb * yCheb;
     524        }
     525    }
    377526    return(polySum);
    378527}
     
    603752    }
    604753
     754    // scale & zero are used for Chebyshev polynomials to define the relationship between
     755    // the independent variables and the normalized version with range -1 : +1.  These
     756    // must be determined for a specific data set.
     757    newPoly->scale[0] = NAN;
     758    newPoly->zero[0]  = NAN;
     759
    605760    return(newPoly);
    606761}
     
    638793            newPoly->coeffMask[x][y] = PS_POLY_MASK_NONE;
    639794        }
     795    }
     796
     797    // scale & zero are used for Chebyshev polynomials to define the relationship between
     798    // the independent variables and the normalized version with range -1 : +1.  These
     799    // must be determined for a specific data set.
     800    for (int i = 0; i < 2; i++) {
     801      newPoly->scale[i] = NAN;
     802      newPoly->zero[i]  = NAN;
    640803    }
    641804
     
    756919            }
    757920        }
     921    }
     922
     923    // scale & zero are used for Chebyshev polynomials to define the relationship between
     924    // the independent variables and the normalized version with range -1 : +1.  These
     925    // must be determined for a specific data set.
     926    for (int i = 0; i < 3; i++) {
     927      newPoly->scale[i] = NAN;
     928      newPoly->zero[i]  = NAN;
    758929    }
    759930
     
    820991    }
    821992
     993    // scale & zero are used for Chebyshev polynomials to define the relationship between
     994    // the independent variables and the normalized version with range -1 : +1.  These
     995    // must be determined for a specific data set.
     996    for (int i = 0; i < 4; i++) {
     997      newPoly->scale[i] = NAN;
     998      newPoly->zero[i]  = NAN;
     999    }
     1000
    8221001    return(newPoly);
    8231002}
    8241003
     1004/* note these functions accept unscaled values and apply the scaling saved on poly */
    8251005psF64 psPolynomial1DEval(const psPolynomial1D* poly,
    8261006                         psF64 x)
     
    8301010    if (poly->type == PS_POLYNOMIAL_ORD) {
    8311011        return(ordPolynomial1DEval(x, poly));
    832     } else if (poly->type == PS_POLYNOMIAL_CHEB) {
     1012    }
     1013    if (poly->type == PS_POLYNOMIAL_CHEB) {
    8331014        return(chebPolynomial1DEval(x, poly));
    834     } else {
    835         psError(PS_ERR_BAD_PARAMETER_TYPE, true,
    836                 _("Unknown polynomial type 0x%x found.  Evaluation failed."),
    837                 poly->type);
    838     }
     1015    }
     1016    psError(PS_ERR_BAD_PARAMETER_TYPE, true,
     1017            _("Unknown polynomial type 0x%x found.  Evaluation failed."),
     1018            poly->type);
     1019
    8391020    return(NAN);
    8401021}
    8411022
    8421023// this function must accept F32 and F64 input x vectors
     1024// EAM XXX these functions seem inefficiently implemented with many nested function calls.
     1025// they might benefit from unrolling.
    8431026psVector *psPolynomial1DEvalVector(const psPolynomial1D *poly,
    8441027                                   const psVector *x)
     
    8781061    if (poly->type == PS_POLYNOMIAL_ORD) {
    8791062        return(ordPolynomial2DEval(x, y, poly));
    880     } else if (poly->type == PS_POLYNOMIAL_CHEB) {
     1063    }
     1064    if (poly->type == PS_POLYNOMIAL_CHEB) {
    8811065        return(chebPolynomial2DEval(x, y, poly));
    882     } else {
    883         psError(PS_ERR_BAD_PARAMETER_TYPE, true,
    884                 _("Unknown polynomial type 0x%x found.  Evaluation failed."),
    885                 poly->type);
    886     }
     1066    }
     1067    psError(PS_ERR_BAD_PARAMETER_TYPE, true,
     1068            _("Unknown polynomial type 0x%x found.  Evaluation failed."),
     1069            poly->type);
    8871070    return(NAN);
     1071}
     1072
     1073psVector *psPolynomial2DEvalChebVector(const psPolynomial2D *poly,
     1074                                       const psVector *x,
     1075                                       const psVector *y)
     1076{
     1077
     1078    if (!isfinite(poly->scale[0]) || !isfinite(poly->zero[0]) || !isfinite(poly->scale[1]) || !isfinite(poly->zero[1])) {
     1079        // re-calculate if not already determined? 
     1080        psError(PS_ERR_UNKNOWN, true, "normalization scales are not set for chebyshev polynomial");
     1081        return (NULL);
     1082    }
     1083
     1084    // Number of polynomial terms
     1085    int nXterm = 1 + poly->nX;      // Number of terms in x
     1086    int nYterm = 1 + poly->nY;      // Number of terms in y
     1087    if (nXterm > 9) {
     1088        psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit: orders higher than 9 are not yet coded\n");
     1089        return NULL;
     1090    }
     1091    if (nYterm > 9) {
     1092        psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit: orders higher than 9 are not yet coded\n");
     1093        return NULL;
     1094    }
     1095
     1096    // Generate normalized vectors for the range -1 : +1.  These functions cast to psF64
     1097    psVector *xNorm = psChebyshevNormVector (poly, x, 0);
     1098    psVector *yNorm = psChebyshevNormVector (poly, y, 1);
     1099   
     1100    // Generate the N cheb polynomials based on xNorm, yNorm
     1101    psArray *xPolySet = psArrayAlloc (nXterm);
     1102    for (int i = 0; i < nXterm; i++) {
     1103        xPolySet->data[i] = psChebyshevPolyVector (xNorm, i);
     1104    }
     1105    psArray *yPolySet = psArrayAlloc (nYterm);
     1106    for (int i = 0; i < nYterm; i++) {
     1107        yPolySet->data[i] = psChebyshevPolyVector (yNorm, i);
     1108    }
     1109
     1110    psVector *out = psVectorAlloc (x->n, PS_TYPE_F64);
     1111
     1112    psF64 *xData = xNorm->data.F64;
     1113    psF64 *yData = yNorm->data.F64;
     1114    psF64 *fData = out->data.F64;
     1115
     1116    // loop over all elements of the data vector
     1117    for (int i = 0; i < x->n; i++) {
     1118
     1119        if (!finite(xData[i])) {fData[i] = NAN; continue; }
     1120        if (!finite(yData[i])) {fData[i] = NAN; continue; }
     1121
     1122        psF64 sum = 0.0;
     1123        for (int jx = 0; jx < nXterm; jx++) {
     1124            psVector *jxCheb = xPolySet->data[jx];
     1125            for (int jy = 0; jy < nYterm; jy++) {
     1126                psVector *jyCheb = yPolySet->data[jy];
     1127                if (poly->coeffMask[jx][jy] & PS_POLY_MASK_SET) continue;
     1128                sum += poly->coeff[jx][jy] * jxCheb->data.F64[i] * jyCheb->data.F64[i];
     1129            }
     1130        }
     1131        fData[i] = sum;
     1132    }
     1133
     1134    psFree (xPolySet);
     1135    psFree (yPolySet);
     1136    psFree (xNorm);
     1137    psFree (yNorm);
     1138
     1139    return out;
    8881140}
    8891141
     
    9011153    PS_ASSERT_VECTOR_TYPE_F32_OR_F64(y, NULL);
    9021154
    903     psVector *tmp;
    904     unsigned int vecLen=x->n;
     1155    unsigned int vecLen = x->n;
     1156
     1157    // input vector types must match
     1158    if (y->type.type != x->type.type) {
     1159        psError(PS_ERR_UNKNOWN, true, "type mismatch in data vectors");
     1160        return (NULL);
     1161    }
    9051162
    9061163    // Determine the length of the output vector to by the minimum of the x,y vectors
    907     if (y->n < vecLen) {
    908         vecLen = y->n;
     1164    // XXX shouldn't we require x & y to have the same length?  seems meaningless otherwise
     1165    if (y->n != vecLen) {
     1166        psError(PS_ERR_UNKNOWN, true, "length mismatch in data vectors");
     1167        return (NULL);
     1168    }
     1169
     1170    if (poly->type == PS_POLYNOMIAL_CHEB) {
     1171        psVector *out = psPolynomial2DEvalChebVector (poly, x, y);
     1172        return out;
    9091173    }
    9101174
    9111175    switch (x->type.type) {
    912     case PS_TYPE_F32:
    913         if (y->type.type != x->type.type) {
    914             psError(PS_ERR_UNKNOWN, true, "type mismatch in data vectors");
    915             return (NULL);
    916         }
    917 
    918         // Create output vector to return
    919         tmp = psVectorAlloc(vecLen, PS_TYPE_F32);
    920 
    921         // Evaluate the polynomial at the specified points
    922         for (unsigned int i=0; i<vecLen; i++) {
    923             tmp->data.F32[i] = psPolynomial2DEval(poly,x->data.F32[i],y->data.F32[i]);
    924         }
    925         break;
    926     case PS_TYPE_F64:
    927         if (y->type.type != x->type.type) {
    928             psError(PS_ERR_UNKNOWN, true, "type mismatch in data vectors");
    929             return (NULL);
    930         }
    931 
    932         // Create output vector to return
    933         tmp = psVectorAlloc(vecLen, PS_TYPE_F64);
    934 
    935         // Evaluate the polynomial at the specified points
    936         for (unsigned int i=0; i<vecLen; i++) {
    937             tmp->data.F64[i] = psPolynomial2DEval(poly,x->data.F64[i],y->data.F64[i]);
    938         }
    939         break;
    940     default:
     1176      case PS_TYPE_F32: {
     1177          // Create output vector to return
     1178          psVector *out = psVectorAlloc(vecLen, PS_TYPE_F32);
     1179
     1180          // Evaluate the polynomial at the specified points
     1181          for (unsigned int i = 0; i < vecLen; i++) {
     1182              out->data.F32[i] = psPolynomial2DEval(poly,x->data.F32[i],y->data.F32[i]);
     1183          }
     1184          return out;
     1185      }
     1186      case PS_TYPE_F64: {
     1187          // Create output vector to return
     1188          psVector *out = psVectorAlloc(vecLen, PS_TYPE_F64);
     1189
     1190          // Evaluate the polynomial at the specified points
     1191          for (unsigned int i = 0; i < vecLen; i++) {
     1192              out->data.F64[i] = psPolynomial2DEval(poly,x->data.F64[i],y->data.F64[i]);
     1193          }
     1194          return out;
     1195      }
     1196      default:
    9411197        psError(PS_ERR_UNKNOWN, false, "invalid input data type.\n");
    9421198        return (NULL);
    9431199    }
    944     // Return output vector
    945     return(tmp);
     1200    psAbort ("impossible");
     1201    return NULL;
    9461202}
    9471203
  • trunk/psLib/src/math/psPolynomial.h

    r15253 r41896  
    6868    psF64 *coeffErr;                    ///< Error in coefficients
    6969    psMaskType *coeffMask;              ///< Coefficient mask
     70    double scale[1];                    ///< Chebyshev scale factor
     71    double zero[1];                     ///< Chebyshev zero point
    7072}
    7173psPolynomial1D;
     
    8082    psF64 **coeffErr;                   ///< Error in coefficients
    8183    psMaskType **coeffMask;                  ///< Coefficients mask
     84    double scale[2];                    ///< Chebyshev scale factor
     85    double zero[2];                     ///< Chebyshev zero point
    8286}
    8387psPolynomial2D;
     
    9397    psF64 ***coeffErr;                  ///< Error in coefficients
    9498    psMaskType ***coeffMask;                 ///< Coefficients mask
     99    double scale[3];                    ///< Chebyshev scale factor
     100    double zero[3];                     ///< Chebyshev zero point
    95101}
    96102psPolynomial3D;
     
    107113    psF64 ****coeffErr;                 ///< Error in coefficients
    108114    psMaskType ****coeffMask;           ///< Coefficients mask
     115    double scale[4];                    ///< Chebyshev scale factor
     116    double zero[4];                     ///< Chebyshev zero point
    109117}
    110118psPolynomial4D;
     
    305313p_chebyPolys;
    306314
     315
     316// chebyshev support functions:
     317bool psChebyshevSetScale (psPolynomial2D* myPoly, const psVector *vec, int dir);
     318psVector *psChebyshevNormVector (const psPolynomial2D* myPoly, const psVector *vec, int dir);
     319psVector *psChebyshevPolyVector (const psVector *vec, int order);
    307320
    308321/*****************************************************************************
Note: See TracChangeset for help on using the changeset viewer.