Changeset 42506
- Timestamp:
- Aug 16, 2023, 10:30:15 AM (3 years ago)
- Location:
- branches/eam_branches/ipp-20230313/psLib
- Files:
-
- 5 edited
-
src/math/psMinimizePolyFit.c (modified) (4 diffs)
-
src/math/psMinimizePolyFit.h (modified) (1 diff)
-
src/math/psPolynomial.c (modified) (7 diffs)
-
src/math/psPolynomial.h (modified) (1 diff)
-
test/math (modified) (1 prop)
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-20230313/psLib/src/math/psMinimizePolyFit.c
r42496 r42506 69 69 if ((ORIG != NULL) && (ORIG->type.type != PS_TYPE_F64)) { psFree(TEMP); } 70 70 71 psVector *psVector_GetModifiedErrors_Caucy 72 ( const psVector *f, 73 const psVector *fEval, 74 const psVector *fErr, 75 const psVector *mask, 76 psVectorMaskType maskValue); 77 71 78 /*****************************************************************************/ 72 79 /* TYPE DEFINITIONS */ … … 90 97 returned as a psVector sums. 91 98 *****************************************************************************/ 92 static psVector *BuildSums1D (93 psVector* sums,94 psF64 x,95 psS32 nTerm)99 static psVector *BuildSums1D 100 ( psVector* sums, 101 psF64 x, 102 psS32 nTerm) 96 103 { 97 104 psS32 nSum = 0; … … 1031 1038 } 1032 1039 1040 // These should probably be tunable: 1041 # define FIT_TOLERANCE 1e-4 1042 # define FLT_TOLERANCE 1e-6 1043 # define WEIGHT_THRESHOLD 0.3 1044 1045 // This function accepts F32 and F64 input vectors. 1046 bool psVectorIRLSFitPolynomial1D( 1047 psPolynomial1D *poly, 1048 psStats *stats, 1049 const psVector *mask, 1050 psVectorMaskType maskValue, 1051 const psVector *f, 1052 const psVector *fErr, 1053 const psVector *xIn) 1054 { 1055 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__); 1056 PS_ASSERT (poly->type == PS_POLYNOMIAL_ORD, false); // XXX for now, only allow ORD 1057 PS_ASSERT_POLY_NON_NULL(poly, false); 1058 PS_ASSERT_VECTOR_NON_NULL(f, false); 1059 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 1060 if (mask != NULL) { 1061 PS_ASSERT_VECTORS_SIZE_EQUAL(mask, f, false); 1062 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 1063 } 1064 if (fErr != NULL) { 1065 PS_ASSERT_VECTORS_SIZE_EQUAL(fErr, f, false); 1066 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false); 1067 } 1068 if (xIn != NULL) { 1069 PS_ASSERT_VECTORS_SIZE_EQUAL(xIn, f, false); 1070 PS_ASSERT_VECTOR_TYPE(xIn, f->type.type, false); 1071 } 1072 1073 // Internal pointers for possibly NULL vectors. 1074 psVector *x = (xIn != NULL) ? psMemIncrRefCounter((psVector *) xIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 1075 1076 // initial fit with nominal errors 1077 if (!psVectorFitPolynomial1D(poly, mask, maskValue, f, fErr, x)) { 1078 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 1079 return false; 1080 } 1081 1082 // use polyOld to save the last fit 1083 psPolynomial1D *polyOld = NULL; 1084 1085 // use clipIter as max number of iterations 1086 bool converged = false; 1087 for (psS32 N = 0; !converged && (N < stats->clipIter); N++) { 1088 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial1D()\n", N); 1089 1090 // evaluate the fit at the input positions 1091 psVector *fEval = psPolynomial1DEvalVector (poly, x); 1092 1093 // calculate modified errors based on the deviation from the fit 1094 psVector *modErr = psVector_GetModifiedErrors_Caucy (f, fEval, fErr, mask, maskValue); 1095 psFree (fEval); 1096 1097 // save the last fit (recycle the structure once allocated) 1098 polyOld = psPolynomial1DCopy (polyOld, poly); 1099 1100 // calculate a new fit with modified errors: 1101 if (!psVectorFitPolynomial1D(poly, mask, maskValue, f, modErr, x)) { 1102 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 1103 psFree(x); 1104 psFree(modErr); 1105 return false; 1106 } 1107 1108 // has the solution converged? 1109 converged = true; 1110 for (int ix = 0; ix <= poly->nX; ix++) { 1111 if ((fabs(poly->coeff[ix] - polyOld->coeff[ix]) > FIT_TOLERANCE * fabs(poly->coeff[ix])) && 1112 (fabs(poly->coeff[ix] - polyOld->coeff[ix]) > FLT_TOLERANCE)) 1113 converged = false; 1114 } 1115 1116 # if (0) 1117 // XXX test: 1118 FILE *ftest = fopen ("irls.wt.dat", "w"); 1119 for (int i = 0; i < modErr->n; i++) { 1120 if (modErr->type.type == PS_TYPE_F64) { 1121 fprintf (ftest, "%d %f\n", i, modErr->data.F64[i]); 1122 } else { 1123 fprintf (ftest, "%d %f\n", i, modErr->data.F32[i]); 1124 } 1125 } 1126 fclose (ftest); 1127 # endif 1128 psFree (modErr); 1129 } 1130 1131 // Free local temporary variables 1132 psFree(x); 1133 psFree(polyOld); 1134 1135 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__); 1136 return true; 1137 } 1138 1139 /****************************************************************************** 1140 ****************************************************************************** 1141 2-D Vector Code. 1142 ****************************************************************************** 1143 *****************************************************************************/ 1144 1145 /****************************************************************************** 1146 VectorFitPolynomial2DOrd(myPoly, *mask, maskValue, *f, *fErr, *x, *y): This is 1147 a private routine which will fit a 2-D polynomial to a set of (x, y)-(f) 1148 pairs. All non-NULL vectors must be of type PS_TYPE_F64. 1149 1150 *****************************************************************************/ 1151 static bool VectorFitPolynomial2DOrd( 1152 psPolynomial2D* myPoly, 1153 const psVector* mask, 1154 psVectorMaskType maskValue, 1155 const psVector *f, 1156 const psVector *fErr, 1157 const psVector *x, 1158 const psVector *y) 1159 { 1160 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__); 1161 PS_ASSERT_POLY_NON_NULL(myPoly, false); 1162 PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, false); 1163 PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, false); 1164 PS_ASSERT_VECTOR_NON_NULL(f, false); 1165 PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, false); 1166 if (fErr != NULL) { 1167 PS_ASSERT_VECTORS_SIZE_EQUAL(y, fErr, false); 1168 PS_ASSERT_VECTOR_TYPE(fErr, PS_TYPE_F64, false); 1169 } 1170 PS_ASSERT_VECTOR_NON_NULL(x, false); 1171 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, false); 1172 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 1173 PS_ASSERT_VECTOR_NON_NULL(y, false); 1174 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, false); 1175 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 1176 if (mask != NULL) { 1177 PS_ASSERT_VECTORS_SIZE_EQUAL(y, mask, false); 1178 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 1179 } 1180 1181 // Number of polynomial terms 1182 int nXterm = 1 + myPoly->nX; // Number of terms in x 1183 int nYterm = 1 + myPoly->nY; // Number of terms in y 1184 int nTerm = nXterm * nYterm; // Total number of terms 1185 1186 psImage *A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64); // Least-squares matrix 1187 psVector *B = psVectorAlloc(nTerm, PS_TYPE_F64); // Least-squares vector 1188 1189 // Initialize data structures. 1190 if (!psImageInit(A, 0.0) || !psVectorInit(B, 0.0)) { 1191 psError(PS_ERR_UNKNOWN, false, "Could initialize data structures A, B. Returning NULL.\n"); 1192 psFree(A); 1193 psFree(B); 1194 psTrace("psLib.math", 6, "---- %s() End ----\n", __func__); 1195 return false; 1196 } 1197 1198 // Dereference stuff, to make the loop go faster 1199 psF64 **matrix = A->data.F64; // Dereference the least-squares matrix 1200 psF64 *vector = B->data.F64; // Dereference the least-squares vector 1201 psMaskType **coeffMask = myPoly->coeffMask; // Dereference mask for polynomial terms 1202 psVectorMaskType *dataMask = NULL; // Dereference mask for data 1203 if (mask) { 1204 dataMask = mask->data.PS_TYPE_VECTOR_MASK_DATA; 1205 } 1206 psF64 *xData = x->data.F64; // Dereference x 1207 psF64 *yData = y->data.F64; // Dereference y 1208 psF64 *fData = f->data.F64; // Dereference f 1209 psF64 *fErrData = NULL; // Dereference fErr 1210 if (fErr) { 1211 fErrData = fErr->data.F64; 1212 } 1213 1214 // Build the least-squares matrix and vector 1215 psImage *xySums = NULL; // The sums: 1, x, x^2, ... x^(2n+1), y, xy, x^2y, ... x^(2n+1) 1216 for (int k = 0; k < x->n; k++) { 1217 if (dataMask && dataMask[k] & maskValue) { 1218 continue; 1219 } 1220 xySums = BuildSums2D(xySums, xData[k], yData[k], nXterm, nYterm); 1221 psF64 **sums = xySums->data.F64;// Dereference sums 1222 1223 double wt; // Weight 1224 if (!fErrData) { 1225 wt = 1.0; 1226 } else { 1227 // this filters fErr == 0 values 1228 wt = (fErrData[k] == 0.0) ? 0.0 : 1.0 / PS_SQR(fErrData[k]); 1229 } 1230 1231 // Iterating over the matrix 1232 for (int i = 0; i < nTerm; i++) { 1233 int l = i / nYterm; // x index 1234 int m = i % nYterm; // y index 1235 if (coeffMask[l][m] & PS_POLY_MASK_SET) { 1236 matrix[i][i] = 1.0; 1237 continue; 1238 } 1239 vector[i] += fData[k] * sums[l][m] * wt; 1240 matrix[i][i] += sums[2*l][2*m] * wt; // The diagonal entry 1241 for (int j = i + 1; j < nTerm; j++) { // Doing the upper diagonal only: we will use symmetry 1242 int p = j / nYterm; // x index 1243 int q = j % nYterm; // y index 1244 if (coeffMask[p][q] & PS_POLY_MASK_SET) { 1245 continue; 1246 } 1247 double value = sums[l+p][m+q] * wt; // Value to add in 1248 matrix[i][j] += value; 1249 matrix[j][i] += value; // Taking advantage of the symmetry 1250 } 1251 } 1252 } 1253 psFree(xySums); 1254 1255 // elements which are masked for fitting need to be subtracted from the vector 1256 for (int i = 0; i < nTerm; i++) { 1257 int ix = i / nYterm; // x index 1258 int iy = i % nYterm; // y index 1259 if (coeffMask[ix][iy] & PS_POLY_MASK_BOTH) { 1260 continue; 1261 } 1262 for (int j = 0; j < nTerm; j++) { // The upper diagonal only: we will use symmetry 1263 int jx = j / nYterm; // x index 1264 int jy = j % nYterm; // y index 1265 if (coeffMask[jx][jy] & PS_POLY_MASK_SET) { 1266 continue; 1267 } 1268 if (!(coeffMask[jx][jy] & PS_POLY_MASK_FIT)) { 1269 continue; 1270 } 1271 vector[i] -= matrix[i][j]*myPoly->coeff[jx][jy]; 1272 } 1273 } 1274 1275 // set the un-fitted and un-set elements to 0 or 1 for pivots 1276 for (int i = 0; i < nTerm; i++) { 1277 int ix = i / nYterm; // x index 1278 int iy = i % nYterm; // y index 1279 if (coeffMask[ix][iy] & PS_POLY_MASK_BOTH) { 1280 for (int j = 0; j < nTerm; j++) { // The upper diagonal only: we will use symmetry 1281 matrix[i][j] = 0.0; 1282 matrix[j][i] = 0.0; 1283 } 1284 matrix[i][i] = 1.0; 1285 continue; 1286 } 1287 } 1288 1289 if (psTraceGetLevel("psLib.math") >= 4) { 1290 printf("Least-squares vector:\n"); 1291 for (int i = 0; i < nTerm; i++) { 1292 printf("%f ", B->data.F64[i]); 1293 } 1294 printf("\n"); 1295 printf("Least-squares matrix:\n"); 1296 for (int i = 0; i < nTerm; i++) { 1297 for (int j = 0; j < nTerm; j++) { 1298 printf("%f ", A->data.F64[i][j]); 1299 } 1300 printf("\n"); 1301 } 1302 } 1303 1304 bool status = false; 1305 if (USE_GAUSS_JORDAN) { 1306 status = psMatrixGJSolve(A, B); 1307 } else { 1308 status = psMatrixLUSolve(A, B); 1309 } 1310 if (!status) { 1311 psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n"); 1312 goto escape; 1313 } 1314 1315 // select the appropriate solution entries (retain the incoming values if masked on the fit) 1316 for (int i = 0; i < nTerm; i++) { 1317 int ix = i / nYterm; // x index 1318 int iy = i % nYterm; // y index 1319 if (coeffMask[ix][iy] & PS_POLY_MASK_FIT) continue; 1320 myPoly->coeff[ix][iy] = B->data.F64[i]; 1321 myPoly->coeffErr[ix][iy] = sqrt(A->data.F64[i][i]); 1322 } 1323 psFree(A); 1324 psFree(B); 1325 return true; 1326 1327 escape: 1328 psFree (A); 1329 psFree (B); 1330 return false; 1331 } 1332 1333 /****************************************************************************** 1334 VectorFitPolynomial2DCheb(myPoly, *mask, maskValue, *f, *fErr, *x, *y): This is 1335 a private routine which will fit a 2-D polynomial to a set of (x, y)-(f) 1336 pairs. All non-NULL vectors must be of type PS_TYPE_F64. 1337 1338 *****************************************************************************/ 1339 static bool VectorFitPolynomial2DCheb( 1340 psPolynomial2D* myPoly, 1341 const psVector *f, 1342 const psVector *x, 1343 const psVector *y) 1344 { 1345 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__); 1346 PS_ASSERT_POLY_NON_NULL(myPoly, false); 1347 PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, false); 1348 PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, false); 1349 PS_ASSERT_VECTOR_NON_NULL(f, false); 1350 PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, false); 1351 PS_ASSERT_VECTOR_NON_NULL(x, false); 1352 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, false); 1353 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 1354 PS_ASSERT_VECTOR_NON_NULL(y, false); 1355 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, false); 1356 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 1357 1358 // Number of polynomial terms 1359 int nXterm = 1 + myPoly->nX; // Number of terms in x 1360 int nYterm = 1 + myPoly->nY; // Number of terms in y 1361 int nTerm = nXterm * nYterm; // Total number of terms 1362 if (nXterm > 9) { 1363 psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit: orders higher than 9 are not yet coded\n"); 1364 return false; 1365 } 1366 if (nYterm > 9) { 1367 psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit: orders higher than 9 are not yet coded\n"); 1368 return false; 1369 } 1370 1371 // determine scale factors 1372 if (!psChebyshevSetScale (myPoly, x, 0)) { psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit.\n"); return false; } 1373 if (!psChebyshevSetScale (myPoly, y, 1)) { psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit.\n"); return false; } 1374 1375 // generate normalized vectors 1376 psVector *xNorm = psChebyshevNormVector (myPoly, x, 0); 1377 psVector *yNorm = psChebyshevNormVector (myPoly, y, 1); 1378 1379 // generate the N cheb polynomials based on xNorm, yNorm 1380 psArray *xPolySet = psArrayAlloc (nXterm); 1381 for (int i = 0; i < nXterm; i++) { 1382 xPolySet->data[i] = psChebyshevPolyVector (xNorm, i); 1383 } 1384 psArray *yPolySet = psArrayAlloc (nYterm); 1385 for (int i = 0; i < nYterm; i++) { 1386 yPolySet->data[i] = psChebyshevPolyVector (yNorm, i); 1387 } 1388 1389 psF64 *fData = f->data.F64; // Dereference f 1390 1391 psImage *A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64); // Least-squares matrix 1392 psVector *B = psVectorAlloc(nTerm, PS_TYPE_F64); // Least-squares vector 1393 1394 // Initialize data structures (should not be able to fail) 1395 psAssert (psImageInit(A, 0.0), "Could initialize data structures A"); 1396 psAssert (psVectorInit(B, 0.0), "Could initialize data structures B"); 1397 1398 // Dereference stuff, to make the loop go faster 1399 psF64 **matrix = A->data.F64; // Dereference the least-squares matrix 1400 psF64 *vector = B->data.F64; // Dereference the least-squares vector 1401 1402 // loop over all elements of the data vector 1403 for (int k = 0; k < x->n; k++) { 1404 1405 if (!finite(fData[k])) continue; 1406 1407 // XXX can we only calculate the upper diagonal? 1408 int nelem = 0; 1409 for (int jx = 0; jx < nXterm; jx++) { 1410 psVector *jxCheb = xPolySet->data[jx]; 1411 for (int jy = 0; jy < nYterm; jy++) { 1412 psVector *jyCheb = yPolySet->data[jy]; 1413 psF64 chebValue = jxCheb->data.F64[k] * jyCheb->data.F64[k]; 1414 1415 vector[nelem] += fData[k] * chebValue; 1416 1417 int melem = 0; 1418 for (int kx = 0; kx < nXterm; kx++) { 1419 psVector *kxCheb = xPolySet->data[kx]; 1420 for (int ky = 0; ky < nYterm; ky++) { 1421 psVector *kyCheb = yPolySet->data[ky]; 1422 matrix[nelem][melem] += chebValue * kxCheb->data.F64[k]*kyCheb->data.F64[k]; 1423 melem++; 1424 } 1425 } 1426 nelem++; 1427 } 1428 } 1429 } 1430 1431 if (psTraceGetLevel("psLib.math") >= 4) { 1432 printf("Least-squares vector:\n"); 1433 for (int i = 0; i < nTerm; i++) { 1434 printf("%f ", B->data.F64[i]); 1435 } 1436 printf("\n"); 1437 printf("Least-squares matrix:\n"); 1438 for (int i = 0; i < nTerm; i++) { 1439 for (int j = 0; j < nTerm; j++) { 1440 printf("%f ", A->data.F64[i][j]); 1441 } 1442 printf("\n"); 1443 } 1444 } 1445 1446 bool status = false; 1447 if (USE_GAUSS_JORDAN) { 1448 status = psMatrixGJSolve(A, B); 1449 } else { 1450 status = psMatrixLUSolve(A, B); 1451 } 1452 if (!status) { 1453 psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n"); 1454 goto escape; 1455 } 1456 1457 // unroll the result: 1458 int nelem = 0; 1459 for (int jx = 0; jx < nXterm; jx++) { 1460 for (int jy = 0; jy < nYterm; jy++) { 1461 myPoly->coeff[jx][jy] = B->data.F64[nelem]; 1462 myPoly->coeffErr[jx][jy] = sqrt(A->data.F64[nelem][nelem]); 1463 nelem ++; 1464 } 1465 } 1466 psFree(A); 1467 psFree(B); 1468 1469 psFree (xNorm); 1470 psFree (yNorm); 1471 psFree (xPolySet); 1472 psFree (yPolySet); 1473 1474 return true; 1475 1476 escape: 1477 psFree (A); 1478 psFree (B); 1479 return false; 1480 } 1481 1482 /****************************************************************************** 1483 psVectorFitPolynomial2D(): This routine fits a 2D polynomial of arbitrary 1484 degree (specified in poly) to the data points (x, y)-(f) and returns that 1485 polynomial. Types F32 and F64 are supported, however, type F32 is done via 1486 vector conversion only. 1487 *****************************************************************************/ 1488 bool psVectorFitPolynomial2D( 1489 psPolynomial2D *poly, 1490 const psVector *mask, 1491 psVectorMaskType maskValue, 1492 const psVector *f, 1493 const psVector *fErr, 1494 const psVector *x, 1495 const psVector *y) 1496 { 1497 PS_ASSERT_POLY_NON_NULL(poly, false); 1498 // PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false); 1499 1500 PS_ASSERT_VECTOR_NON_NULL(f, false); 1501 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 1502 PS_ASSERT_VECTOR_NON_NULL(x, false); 1503 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 1504 PS_ASSERT_VECTOR_NON_NULL(y, false); 1505 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 1506 if (mask != NULL) { 1507 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false); 1508 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 1509 } 1510 if (fErr != NULL) { 1511 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false); 1512 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(fErr, false); 1513 } 1514 1515 // Convert input vectors to F64 if necessary. 1516 psVector *f64 = (f->type.type == PS_TYPE_F64) ? (psVector *) f : psVectorCopy(NULL, f, PS_TYPE_F64); 1517 psVector *x64 = (x->type.type == PS_TYPE_F64) ? (psVector *) x : psVectorCopy(NULL, x, PS_TYPE_F64); 1518 psVector *y64 = (y->type.type == PS_TYPE_F64) ? (psVector *) y : psVectorCopy(NULL, y, PS_TYPE_F64); 1519 1520 psVector *fErr64 = NULL; 1521 if (fErr != NULL) { 1522 fErr64 = (fErr->type.type == PS_TYPE_F64) ? (psVector *) fErr : psVectorCopy(NULL, fErr, PS_TYPE_F64); 1523 } 1524 1525 bool result = true; 1526 1527 switch (poly->type) { 1528 case PS_POLYNOMIAL_ORD: 1529 result = VectorFitPolynomial2DOrd(poly, mask, maskValue, f64, fErr64, x64, y64); 1530 if (!result) { 1531 psError(PS_ERR_UNKNOWN, true, "Could not fit polynomial. Returning NULL.\n"); 1532 } 1533 break; 1534 case PS_POLYNOMIAL_CHEB: 1535 if (mask != NULL) { 1536 psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring mask and maskValue with Chebyshev polynomials.\n"); 1537 } 1538 if (fErr != NULL) { 1539 psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring error values for Chebyshev polynomials.\n"); 1540 } 1541 result = VectorFitPolynomial2DCheb(poly, f64, x64, y64); 1542 if (!result) { 1543 psError(PS_ERR_UNKNOWN, true, "Could not fit polynomial. Returning NULL.\n"); 1544 } 1545 break; 1546 default: 1547 psError(PS_ERR_UNKNOWN, true, "Incorrect polynomial type. Returning NULL.\n"); 1548 result = false; 1549 break; 1550 } 1551 1552 // Free psVectors that were created for NULL arguments. 1553 PS_FREE_TEMP_F64_VECTOR (f, f64); 1554 PS_FREE_TEMP_F64_VECTOR (x, x64); 1555 PS_FREE_TEMP_F64_VECTOR (y, y64); 1556 PS_FREE_TEMP_F64_VECTOR (fErr, fErr64); 1557 1558 return result; 1559 } 1560 1561 bool psVectorClipFitPolynomial2D( 1562 psPolynomial2D *poly, 1563 psStats *stats, 1564 const psVector *mask, 1565 psVectorMaskType maskValue, 1566 const psVector *f, 1567 const psVector *fErr, 1568 const psVector *x, 1569 const psVector *y) 1570 { 1571 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__); 1572 PS_ASSERT_POLY_NON_NULL(poly, false); 1573 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false); 1574 PS_ASSERT_PTR_NON_NULL(stats, false); 1575 PS_ASSERT_VECTOR_NON_NULL(mask, false); 1576 PS_ASSERT_VECTOR_NON_NULL(f, false); 1577 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 1578 1579 PS_ASSERT_VECTOR_NON_NULL(x, false); 1580 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 1581 PS_ASSERT_VECTOR_TYPE(x, f->type.type, false); 1582 1583 PS_ASSERT_VECTOR_NON_NULL(y, false); 1584 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 1585 PS_ASSERT_VECTOR_TYPE(y, f->type.type, false); 1586 1587 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false); 1588 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 1589 1590 if (fErr != NULL) { 1591 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false); 1592 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false); 1593 } 1594 1595 // the user supplies one of various stats option pairs, 1596 // determine the desired mean and stdev STATS options: 1597 // XXX enforce consistency? 1598 // XXX psStatsGetValue() probably has inverted precedence 1599 psStatsOptions meanOption = stats->options & (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN | PS_STAT_ROBUST_MEDIAN | PS_STAT_CLIPPED_MEAN | PS_STAT_FITTED_MEAN | PS_STAT_FITTED_MEAN); 1600 psStatsOptions stdevOption = stats->options & (PS_STAT_SAMPLE_STDEV | PS_STAT_ROBUST_STDEV | PS_STAT_CLIPPED_STDEV | PS_STAT_FITTED_STDEV | PS_STAT_FITTED_STDEV); 1601 if (!meanOption) { 1602 psError(PS_ERR_UNKNOWN, true, "no valid mean stats option selected"); 1603 return false; 1604 } 1605 if (!stdevOption) { 1606 psError(PS_ERR_UNKNOWN, true, "no valid stdev stats option selected"); 1607 return false; 1608 } 1609 1610 // clipping range defined by min and max and/or clipSigma 1611 psF32 minClipSigma; 1612 psF32 maxClipSigma; 1613 if (isfinite(stats->max)) { 1614 maxClipSigma = fabs(stats->max); 1615 } else { 1616 maxClipSigma = fabs(stats->clipSigma); 1617 } 1618 if (isfinite(stats->min)) { 1619 minClipSigma = fabs(stats->min); 1620 } else { 1621 minClipSigma = fabs(stats->clipSigma); 1622 } 1623 psVector *resid = psVectorAlloc(f->n, PS_TYPE_F64); 1624 1625 psTrace("psLib.math", 4, "stats->clipIter is %d\n", stats->clipIter); 1626 psTrace("psLib.math", 4, "(minClipSigma, maxClipSigma) is (%.2f, %.2f)\n", minClipSigma, maxClipSigma); 1627 1628 for (psS32 N = 0; N < stats->clipIter; N++) { 1629 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial1D()\n", N); 1630 psS32 Nkeep = 0; 1631 if (psTraceGetLevel("psLib.math") >= 7) { 1632 if (mask != NULL) { 1633 for (psS32 i = 0 ; i < mask->n ; i++) { 1634 psTrace("psLib.math", 7, "mask[%d] is %d\n", i, mask->data.PS_TYPE_VECTOR_MASK_DATA[i]); 1635 } 1636 } 1637 } 1638 1639 if (!psVectorFitPolynomial2D(poly, mask, maskValue, f, fErr, x, y)) { 1640 psError(PS_ERR_UNKNOWN, false, "Could not fit a polynomial to the data. Returning false.\n"); 1641 psFree(resid); 1642 return false; 1643 } 1644 1645 psVector *fit = psPolynomial2DEvalVector(poly, x, y); 1646 if (fit == NULL) { 1647 psError(PS_ERR_UNKNOWN, false, "Could not call psPolynomial3DEvalVector(). Returning NULL.\n"); 1648 psFree(resid); 1649 return false; 1650 } 1651 1652 for (psS32 i = 0 ; i < f->n ; i++) { 1653 if (f->type.type == PS_TYPE_F64) { 1654 resid->data.F64[i] = f->data.F64[i] - fit->data.F64[i]; 1655 } else { 1656 resid->data.F64[i] = (psF64) (f->data.F32[i] - fit->data.F32[i]); 1657 } 1658 } 1659 1660 if (psTraceGetLevel("psLib.math") >= 7) { 1661 if (mask != NULL) { 1662 for (psS32 i = 0 ; i < mask->n ; i++) { 1663 if (!((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue))) { 1664 psTrace("psLib.math", 7, "point %d at %f %f : value, fit : %f %f resid: %f\n", 1665 i, x->data.F32[i], y->data.F32[i], f->data.F32[i], fit->data.F32[i], resid->data.F64[i]); 1666 } 1667 } 1668 } 1669 } 1670 1671 if (!psVectorStats(stats, resid, NULL, mask, maskValue)) { 1672 psError(PS_ERR_UNKNOWN, false, "Could not compute statistics on the resid vector. Returning NULL.\n"); 1673 psFree(resid); 1674 psFree(fit); 1675 return false; 1676 } 1677 1678 double meanValue = psStatsGetValue (stats, meanOption); 1679 double stdevValue = psStatsGetValue (stats, stdevOption); 1680 1681 psTrace("psLib.math", 5, "Mean is %f\n", meanValue); 1682 psTrace("psLib.math", 5, "Stdev is %f\n", stdevValue); 1683 psF32 minClipValue = -minClipSigma*stdevValue; 1684 psF32 maxClipValue = +maxClipSigma*stdevValue; 1685 1686 // set mask if pts are not valid 1687 // we are masking out any point which is out of range 1688 // recovery is not allowed with this scheme 1689 for (psS32 i = 0; i < resid->n; i++) { 1690 if ((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) { 1691 continue; 1692 } 1693 1694 if ((resid->data.F64[i] - meanValue > maxClipValue) || (resid->data.F64[i] - meanValue < minClipValue)) { 1695 if (fit->type.type == PS_TYPE_F64) { 1696 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n", 1697 i, fit->data.F64[i], i, resid->data.F64[i]); 1698 } else { 1699 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n", 1700 i, fit->data.F32[i], i, resid->data.F64[i]); 1701 } 1702 1703 if (mask != NULL) { 1704 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= 0x01; 1705 } 1706 continue; 1707 } 1708 Nkeep++; 1709 } 1710 psTrace("psLib.math", 4, "keeping %d of %ld pts for fit\n", Nkeep, x->n); 1711 stats->clippedNvalues = Nkeep; 1712 psFree(fit); 1713 } 1714 // Free local temporary variables 1715 psFree(resid); 1716 1717 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__); 1718 return true; 1719 } 1720 1721 // This function accepts F32 and F64 input vectors. 1722 bool psVectorIRLSFitPolynomial2D( 1723 psPolynomial2D *poly, 1724 psStats *stats, 1725 const psVector *mask, 1726 psVectorMaskType maskValue, 1727 const psVector *f, 1728 const psVector *fErr, 1729 const psVector *xIn, 1730 const psVector *yIn) 1731 { 1732 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__); 1733 1734 PS_ASSERT (poly->type == PS_POLYNOMIAL_ORD, false); // XXX for now, only allow ORD 1735 PS_ASSERT_POLY_NON_NULL(poly, false); 1736 PS_ASSERT_VECTOR_NON_NULL(f, false); 1737 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 1738 if (mask != NULL) { 1739 PS_ASSERT_VECTORS_SIZE_EQUAL(mask, f, false); 1740 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 1741 } 1742 if (fErr != NULL) { 1743 PS_ASSERT_VECTORS_SIZE_EQUAL(fErr, f, false); 1744 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false); 1745 } 1746 if (xIn != NULL) { 1747 PS_ASSERT_VECTORS_SIZE_EQUAL(xIn, f, false); 1748 PS_ASSERT_VECTOR_TYPE(xIn, f->type.type, false); 1749 } 1750 if (yIn != NULL) { 1751 PS_ASSERT_VECTORS_SIZE_EQUAL(yIn, f, false); 1752 PS_ASSERT_VECTOR_TYPE(yIn, f->type.type, false); 1753 } 1754 1755 // Internal pointers for possibly NULL vectors. 1756 psVector *x = (xIn != NULL) ? psMemIncrRefCounter((psVector *) xIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 1757 psVector *y = (yIn != NULL) ? psMemIncrRefCounter((psVector *) yIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 1758 1759 // initial fit with nominal errors 1760 if (!psVectorFitPolynomial2D(poly, mask, maskValue, f, fErr, x, y)) { 1761 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 1762 psFree(x); 1763 psFree(y); 1764 return false; 1765 } 1766 1767 // use polyOld to save the last fit 1768 psPolynomial2D *polyOld = NULL; 1769 1770 // use clipIter as max number of iterations 1771 bool converged = false; 1772 for (psS32 N = 0; !converged && (N < stats->clipIter); N++) { 1773 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial2D()\n", N); 1774 1775 // evaluate the fit at the input positions 1776 psVector *fEval = psPolynomial2DEvalVector (poly, x, y); 1777 1778 // calculate modified errors based on the deviation from the fit 1779 psVector *modErr = psVector_GetModifiedErrors_Caucy (f, fEval, fErr, mask, maskValue); 1780 psFree (fEval); 1781 1782 // save the last fit (recycle the structure once allocated) 1783 polyOld = psPolynomial2DCopy (polyOld, poly); 1784 1785 // calculate a new fit with modified errors: 1786 if (!psVectorFitPolynomial2D(poly, mask, maskValue, f, modErr, x, y)) { 1787 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 1788 psFree(x); 1789 psFree(y); 1790 psFree(modErr); 1791 return false; 1792 } 1793 1794 // has the solution converged? 1795 converged = true; 1796 for (int ix = 0; ix <= poly->nX; ix++) { 1797 for (int iy = 0; iy <= poly->nY; iy++) { 1798 if ((fabs(poly->coeff[ix][iy] - polyOld->coeff[ix][iy]) > FIT_TOLERANCE * fabs(poly->coeff[ix][iy])) && 1799 (fabs(poly->coeff[ix][iy] - polyOld->coeff[ix][iy]) > FLT_TOLERANCE)) 1800 converged = false; 1801 } 1802 } 1803 psFree (modErr); 1804 } 1805 1806 // Free local temporary variables 1807 psFree(x); 1808 psFree(y); 1809 psFree(polyOld); 1810 1811 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__); 1812 return true; 1813 } 1814 1815 /****************************************************************************** 1816 ****************************************************************************** 1817 3-D Vector Code. 1818 ****************************************************************************** 1819 *****************************************************************************/ 1820 1821 /****************************************************************************** 1822 VectorFitPolynomial3DOrd(myPoly, *mask, maskValue, *f, *fErr, *x, *y, *z): 1823 This is a private routine which will fit a 3-D polynomial to a set of (x, 1824 y, z)-(f) pairs. All non-NULL vectors must be of type PS_TYPE_F64. 1825 1826 *****************************************************************************/ 1827 static bool VectorFitPolynomial3DOrd( 1828 psPolynomial3D* myPoly, 1829 const psVector* mask, 1830 psVectorMaskType maskValue, 1831 const psVector *f, 1832 const psVector *fErr, 1833 const psVector *x, 1834 const psVector *y, 1835 const psVector *z) 1836 { 1837 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__); 1838 PS_ASSERT_POLY_NON_NULL(myPoly, false); 1839 PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, false); 1840 PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, false); 1841 PS_ASSERT_INT_NONNEGATIVE(myPoly->nZ, false); 1842 1843 PS_ASSERT_VECTOR_NON_NULL(f, false); 1844 PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, false); 1845 if (fErr != NULL) { 1846 PS_ASSERT_VECTORS_SIZE_EQUAL(y, fErr, false); 1847 PS_ASSERT_VECTOR_TYPE(fErr, PS_TYPE_F64, false); 1848 } 1849 PS_ASSERT_VECTOR_NON_NULL(x, false); 1850 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, false); 1851 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 1852 PS_ASSERT_VECTOR_NON_NULL(y, false); 1853 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, false); 1854 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 1855 PS_ASSERT_VECTOR_NON_NULL(z, false); 1856 PS_ASSERT_VECTOR_TYPE(z, PS_TYPE_F64, false); 1857 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false); 1858 if (mask != NULL) { 1859 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false); 1860 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 1861 } 1862 1863 int nXterm = 1 + myPoly->nX; // Number of x terms 1864 int nYterm = 1 + myPoly->nY; // Number of y terms 1865 int nZterm = 1 + myPoly->nZ; // Number of z terms 1866 int nTerm = nXterm * nYterm * nZterm; // Total number of terms 1867 int nData = x->n; // Number of data points 1868 psImage *A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64); // Least-squares matrix 1869 psVector *B = psVectorAlloc(nTerm, PS_TYPE_F64); // Least-squares vector 1870 1871 // Initialize data structures. 1872 if (!psImageInit(A, 0.0) || !psVectorInit(B, 0.0)) { 1873 psError(PS_ERR_UNKNOWN, false, "Could initialize data structures A, B. Returning NULL.\n"); 1874 psFree(A); 1875 psFree(B); 1876 psTrace("psLib.math", 4, "---- %s() End ----\n", __func__); 1877 return false; 1878 } 1879 1880 // Dereference points for speed in the loop 1881 psF64 **matrix = A->data.F64; // Least-squares matrix 1882 psF64 *vector = B->data.F64; // Least-squares vector 1883 psF64 *xData = x->data.F64; // x 1884 psF64 *yData = y->data.F64; // y 1885 psF64 *zData = z->data.F64; // z 1886 psF64 *fData = f->data.F64; // f 1887 psF64 *fErrData = NULL; // Error in f 1888 if (fErr) { 1889 fErrData = fErr->data.F64; 1890 } 1891 psVectorMaskType *dataMask = NULL; // Mask for data 1892 if (mask) { 1893 dataMask = mask->data.PS_TYPE_VECTOR_MASK_DATA; 1894 } 1895 psMaskType ***coeffMask = myPoly->coeffMask; // Mask for polynomial terms 1896 int nYZterm = nYterm * nZterm; // Multiplication of the numbers, to calculate the index 1897 1898 // Build the B and A data structs. 1899 psF64 ***Sums = NULL; // Sums look like: 1, x, x^2, ... x^(2n+1), y, xy, x^2y, ... x^(2n+1)*y, ... 1900 for (int k = 0; k < nData; k++) { 1901 if (dataMask && dataMask[k] & maskValue) { 1902 continue; 1903 } 1904 1905 Sums = BuildSums3D(Sums, xData[k], yData[k], zData[k], nXterm, nYterm, nZterm); 1906 1907 double wt; 1908 if (fErr == NULL) { 1909 wt = 1.0; 1910 } else { 1911 // this filters fErr == 0 values 1912 wt = (fErr->data.F64[k] == 0.0) ? 0.0 : 1.0 / PS_SQR(fErrData[k]); 1913 } 1914 1915 for (int i = 0; i < nTerm; i++) { 1916 int ix = i / nYZterm; // x index 1917 int iy = (i % nYZterm) / nZterm; // y index 1918 int iz = (i % nYZterm) % nZterm; // z index 1919 if (coeffMask[ix][iy][iz] & PS_POLY_MASK_BOTH) { 1920 matrix[i][i] = 1.0; 1921 continue; 1922 } 1923 1924 vector[i] += fData[k] * Sums[ix][iy][iz] * wt; 1925 matrix[i][i] += Sums[2*ix][2*iy][2*iz] * wt; 1926 for (int j = i + 1; j < nTerm; j++) { 1927 int jx = j / (nYZterm); // x index 1928 int jy = (j % nYZterm) / nZterm; // y index 1929 int jz = (j % nYZterm) % nZterm; // z index 1930 if (coeffMask[jx][jy][jz] & PS_POLY_MASK_BOTH) { 1931 continue; 1932 } 1933 double value = Sums[ix+jx][iy+jy][iz+jz] * wt; 1934 matrix[i][j] += value; 1935 matrix[j][i] += value; 1936 } 1937 } 1938 } 1939 1940 // Free the sums 1941 for (psS32 ix = 0; ix < 2*nXterm; ix++) { 1942 for (psS32 iy = 0; iy < 2*nYterm; iy++) { 1943 psFree(Sums[ix][iy]); 1944 } 1945 psFree(Sums[ix]); 1946 } 1947 psFree(Sums); 1948 1949 1950 bool status = false; 1951 if (USE_GAUSS_JORDAN) { 1952 status = psMatrixGJSolve(A, B); 1953 } else { 1954 status = psMatrixLUSolve(A, B); 1955 } 1956 if (!status) { 1957 psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n"); 1958 goto escape; 1959 } 1960 1961 // select the appropriate solution entries 1962 for (int i = 0; i < nTerm; i++) { 1963 int ix = i / nYZterm; // x index 1964 int iy = (i % nYZterm) / nZterm; // y index 1965 int iz = (i % nYZterm) % nZterm; // z index 1966 if (coeffMask[ix][iy][iz] & PS_POLY_MASK_FIT) continue; 1967 myPoly->coeff[ix][iy][iz] = B->data.F64[i]; 1968 myPoly->coeffErr[ix][iy][iz] = sqrt(A->data.F64[i][i]); 1969 } 1970 psFree(A); 1971 psFree(B); 1972 return true; 1973 1974 escape: 1975 psFree(A); 1976 psFree(B); 1977 return false; 1978 } 1979 1980 /****************************************************************************** 1981 psVectorFitPolynomial3D(): This routine fits a 3D polynomial of arbitrary 1982 degree (specified in poly) to the data points (x, y, z)-(f) and returns that 1983 polynomial. Types F32 and F64 are supported, however, type F32 is done via 1984 vector conversion only. 1985 *****************************************************************************/ 1986 bool psVectorFitPolynomial3D( 1987 psPolynomial3D *poly, 1988 const psVector *mask, 1989 psVectorMaskType maskValue, 1990 const psVector *f, 1991 const psVector *fErr, 1992 const psVector *x, 1993 const psVector *y, 1994 const psVector *z) 1995 { 1996 PS_ASSERT_POLY_NON_NULL(poly, false); 1997 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false); 1998 1999 PS_ASSERT_VECTOR_NON_NULL(f, false); 2000 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 2001 PS_ASSERT_VECTOR_NON_NULL(x, false); 2002 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 2003 PS_ASSERT_VECTOR_NON_NULL(y, false); 2004 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 2005 PS_ASSERT_VECTOR_NON_NULL(z, false); 2006 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false); 2007 if (mask != NULL) { 2008 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false); 2009 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 2010 } 2011 if (fErr != NULL) { 2012 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false); 2013 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(fErr, false); 2014 } 2015 2016 // Convert input vectors to F64 if necessary. 2017 psVector *f64 = (f->type.type == PS_TYPE_F64) ? (psVector *) f : psVectorCopy(NULL, f, PS_TYPE_F64); 2018 psVector *x64 = (x->type.type == PS_TYPE_F64) ? (psVector *) x : psVectorCopy(NULL, x, PS_TYPE_F64); 2019 psVector *y64 = (y->type.type == PS_TYPE_F64) ? (psVector *) y : psVectorCopy(NULL, y, PS_TYPE_F64); 2020 psVector *z64 = (z->type.type == PS_TYPE_F64) ? (psVector *) z : psVectorCopy(NULL, z, PS_TYPE_F64); 2021 2022 psVector *fErr64 = NULL; 2023 if (fErr != NULL) { 2024 fErr64 = (fErr->type.type == PS_TYPE_F64) ? (psVector *) fErr : psVectorCopy(NULL, fErr, PS_TYPE_F64); 2025 } 2026 2027 bool result = true; 2028 2029 switch (poly->type) { 2030 case PS_POLYNOMIAL_ORD: 2031 result = VectorFitPolynomial3DOrd(poly, mask, maskValue, f64, fErr64, x64, y64, z64); 2032 if (!result) { 2033 psError(PS_ERR_UNKNOWN, true, "Could not fit polynomial. Returning NULL.\n"); 2034 } 2035 break; 2036 case PS_POLYNOMIAL_CHEB: 2037 if (mask != NULL) { 2038 psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring mask and maskValue with Chebyshev polynomials.\n"); 2039 } 2040 psError(PS_ERR_UNKNOWN, true, "3-D Chebyshev polynomial vector fitting has not been implemented. Returning NULL.\n"); 2041 result = false; 2042 break; 2043 default: 2044 psError(PS_ERR_UNKNOWN, true, "Incorrect polynomial type. Returning NULL.\n"); 2045 result = false; 2046 break; 2047 } 2048 2049 // Free psVectors that were created for NULL arguments. 2050 PS_FREE_TEMP_F64_VECTOR (f, f64); 2051 PS_FREE_TEMP_F64_VECTOR (x, x64); 2052 PS_FREE_TEMP_F64_VECTOR (y, y64); 2053 PS_FREE_TEMP_F64_VECTOR (z, z64); 2054 PS_FREE_TEMP_F64_VECTOR (fErr, fErr64); 2055 2056 return result; 2057 } 2058 2059 bool psVectorClipFitPolynomial3D( 2060 psPolynomial3D *poly, 2061 psStats *stats, 2062 const psVector *mask, 2063 psVectorMaskType maskValue, 2064 const psVector *f, 2065 const psVector *fErr, 2066 const psVector *x, 2067 const psVector *y, 2068 const psVector *z) 2069 { 2070 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__); 2071 PS_ASSERT_POLY_NON_NULL(poly, false); 2072 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false); 2073 PS_ASSERT_PTR_NON_NULL(stats, false); 2074 PS_ASSERT_VECTOR_NON_NULL(mask, false); 2075 PS_ASSERT_VECTOR_NON_NULL(f, false); 2076 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 2077 2078 PS_ASSERT_VECTOR_NON_NULL(x, false); 2079 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 2080 PS_ASSERT_VECTOR_TYPE(x, f->type.type, false); 2081 2082 PS_ASSERT_VECTOR_NON_NULL(y, false); 2083 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 2084 PS_ASSERT_VECTOR_TYPE(y, f->type.type, false); 2085 2086 PS_ASSERT_VECTOR_NON_NULL(z, false); 2087 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false); 2088 PS_ASSERT_VECTOR_TYPE(z, f->type.type, false); 2089 2090 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false); 2091 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 2092 2093 if (fErr != NULL) { 2094 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false); 2095 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false); 2096 } 2097 2098 // the user supplies one of various stats option pairs, 2099 // determine the desired mean and stdev STATS options: 2100 // XXX enforce consistency? 2101 // XXX psStatsGetValue() probably has inverted precedence 2102 psStatsOptions meanOption = stats->options & (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN | PS_STAT_ROBUST_MEDIAN | PS_STAT_CLIPPED_MEAN | PS_STAT_FITTED_MEAN | PS_STAT_FITTED_MEAN); 2103 psStatsOptions stdevOption = stats->options & (PS_STAT_SAMPLE_STDEV | PS_STAT_ROBUST_STDEV | PS_STAT_CLIPPED_STDEV | PS_STAT_FITTED_STDEV | PS_STAT_FITTED_STDEV); 2104 if (!meanOption) { 2105 psError(PS_ERR_UNKNOWN, true, "no valid mean stats option selected"); 2106 return false; 2107 } 2108 if (!stdevOption) { 2109 psError(PS_ERR_UNKNOWN, true, "no valid stdev stats option selected"); 2110 return false; 2111 } 2112 2113 // clipping range defined by min and max and/or clipSigma 2114 psF32 minClipSigma; 2115 psF32 maxClipSigma; 2116 if (isfinite(stats->max)) { 2117 maxClipSigma = fabs(stats->max); 2118 } else { 2119 maxClipSigma = fabs(stats->clipSigma); 2120 } 2121 if (isfinite(stats->min)) { 2122 minClipSigma = fabs(stats->min); 2123 } else { 2124 minClipSigma = fabs(stats->clipSigma); 2125 } 2126 psVector *resid = psVectorAlloc(f->n, PS_TYPE_F64); 2127 2128 psTrace("psLib.math", 4, "stats->clipIter is %d\n", stats->clipIter); 2129 psTrace("psLib.math", 4, "(minClipSigma, maxClipSigma) is (%.2f, %.2f)\n", minClipSigma, maxClipSigma); 2130 2131 for (psS32 N = 0; N < stats->clipIter; N++) { 2132 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial1D()\n", N); 2133 psS32 Nkeep = 0; 2134 if (psTraceGetLevel("psLib.math") >= 6) { 2135 if (mask != NULL) { 2136 for (psS32 i = 0 ; i < mask->n ; i++) { 2137 psTrace("psLib.math", 6, "mask[%d] is %d\n", i, mask->data.PS_TYPE_VECTOR_MASK_DATA[i]); 2138 } 2139 } 2140 } 2141 2142 if (!psVectorFitPolynomial3D(poly, mask, maskValue, f, fErr, x, y, z)) { 2143 psError(PS_ERR_UNKNOWN, false, "Could not fit a polynomial to the data. Returning NULL.\n"); 2144 psFree(resid); 2145 return false; 2146 } 2147 psVector *fit = psPolynomial3DEvalVector(poly, x, y, z); 2148 if (fit == NULL) { 2149 psError(PS_ERR_UNKNOWN, false, "Could not call psPolynomial3DEvalVector(). Returning NULL.\n"); 2150 psFree(resid); 2151 return false; 2152 } 2153 for (psS32 i = 0 ; i < f->n ; i++) { 2154 if (f->type.type == PS_TYPE_F64) { 2155 resid->data.F64[i] = f->data.F64[i] - fit->data.F64[i]; 2156 } else { 2157 resid->data.F64[i] = ((psF64) f->data.F32[i]) - fit->data.F64[i]; 2158 } 2159 } 2160 2161 if (psTraceGetLevel("psLib.math") >= 6) { 2162 if (mask != NULL) { 2163 for (psS32 i = 0 ; i < mask->n ; i++) { 2164 if (!((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue))) { 2165 psTrace("psLib.math", 6, "(f, fit)[%d] is (%f, %f). resid is (%f)\n", 2166 i, f->data.F32[i], fit->data.F32[i], resid->data.F64[i]); 2167 } 2168 } 2169 } 2170 } 2171 2172 if (!psVectorStats(stats, resid, NULL, mask, maskValue)) { 2173 psError(PS_ERR_UNKNOWN, false, "Could not compute statistics on the resid vector. Returning NULL.\n"); 2174 psFree(resid); 2175 psFree(fit); 2176 return false; 2177 } 2178 2179 double meanValue = psStatsGetValue (stats, meanOption); 2180 double stdevValue = psStatsGetValue (stats, stdevOption); 2181 2182 psTrace("psLib.math", 5, "Mean is %f\n", meanValue); 2183 psTrace("psLib.math", 5, "Stdev is %f\n", stdevValue); 2184 psF32 minClipValue = -minClipSigma*stdevValue; 2185 psF32 maxClipValue = +maxClipSigma*stdevValue; 2186 2187 // set mask if pts are not valid 2188 // we are masking out any point which is out of range 2189 // recovery is not allowed with this scheme 2190 for (psS32 i = 0; i < resid->n; i++) { 2191 if ((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) { 2192 continue; 2193 } 2194 2195 if ((resid->data.F64[i] - meanValue > maxClipValue) || (resid->data.F64[i] - meanValue < minClipValue)) { 2196 if (f->type.type == PS_TYPE_F64) { 2197 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n", 2198 i, fit->data.F64[i], i, resid->data.F64[i]); 2199 } else { 2200 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n", 2201 i, fit->data.F32[i], i, resid->data.F64[i]); 2202 } 2203 2204 if (mask != NULL) { 2205 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= 0x01; 2206 } 2207 continue; 2208 } 2209 Nkeep++; 2210 } 2211 psTrace("psLib.math", 6, "keeping %d of %ld pts for fit\n", Nkeep, x->n); 2212 stats->clippedNvalues = Nkeep; 2213 psFree(fit); 2214 } 2215 // Free local temporary variables 2216 psFree(resid); 2217 2218 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__); 2219 return true; 2220 } 2221 2222 // This function accepts F32 and F64 input vectors. 2223 bool psVectorIRLSFitPolynomial3D( 2224 psPolynomial3D *poly, 2225 psStats *stats, 2226 const psVector *mask, 2227 psVectorMaskType maskValue, 2228 const psVector *f, 2229 const psVector *fErr, 2230 const psVector *xIn, 2231 const psVector *yIn, 2232 const psVector *zIn) 2233 { 2234 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__); 2235 2236 PS_ASSERT (poly->type == PS_POLYNOMIAL_ORD, false); // XXX for now, only allow ORD 2237 PS_ASSERT_POLY_NON_NULL(poly, false); 2238 PS_ASSERT_VECTOR_NON_NULL(f, false); 2239 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 2240 if (mask != NULL) { 2241 PS_ASSERT_VECTORS_SIZE_EQUAL(mask, f, false); 2242 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 2243 } 2244 if (fErr != NULL) { 2245 PS_ASSERT_VECTORS_SIZE_EQUAL(fErr, f, false); 2246 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false); 2247 } 2248 if (xIn != NULL) { 2249 PS_ASSERT_VECTORS_SIZE_EQUAL(xIn, f, false); 2250 PS_ASSERT_VECTOR_TYPE(xIn, f->type.type, false); 2251 } 2252 if (yIn != NULL) { 2253 PS_ASSERT_VECTORS_SIZE_EQUAL(yIn, f, false); 2254 PS_ASSERT_VECTOR_TYPE(yIn, f->type.type, false); 2255 } 2256 if (zIn != NULL) { 2257 PS_ASSERT_VECTORS_SIZE_EQUAL(zIn, f, false); 2258 PS_ASSERT_VECTOR_TYPE(zIn, f->type.type, false); 2259 } 2260 2261 // Internal pointers for possibly NULL vectors. 2262 psVector *x = (xIn != NULL) ? psMemIncrRefCounter((psVector *) xIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 2263 psVector *y = (yIn != NULL) ? psMemIncrRefCounter((psVector *) yIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 2264 psVector *z = (zIn != NULL) ? psMemIncrRefCounter((psVector *) zIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 2265 2266 // initial fit with nominal errors 2267 if (!psVectorFitPolynomial3D(poly, mask, maskValue, f, fErr, x, y, z)) { 2268 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 2269 psFree(x); 2270 psFree(y); 2271 psFree(z); 2272 return false; 2273 } 2274 2275 // use polyOld to save the last fit 2276 psPolynomial3D *polyOld = NULL; 2277 2278 // use clipIter as max number of iterations 2279 bool converged = false; 2280 for (psS32 N = 0; !converged && (N < stats->clipIter); N++) { 2281 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial3D()\n", N); 2282 2283 // evaluate the fit at the input positions 2284 psVector *fEval = psPolynomial3DEvalVector (poly, x, y, z); 2285 2286 // calculate modified errors based on the deviation from the fit 2287 psVector *modErr = psVector_GetModifiedErrors_Caucy (f, fEval, fErr, mask, maskValue); 2288 psFree (fEval); 2289 2290 // save the last fit (recycle the structure once allocated) 2291 polyOld = psPolynomial3DCopy (polyOld, poly); 2292 2293 // calculate a new fit with modified errors: 2294 if (!psVectorFitPolynomial3D(poly, mask, maskValue, f, modErr, x, y, z)) { 2295 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 2296 psFree(x); 2297 psFree(y); 2298 psFree(z); 2299 psFree(modErr); 2300 return false; 2301 } 2302 2303 // has the solution converged? 2304 converged = true; 2305 for (int ix = 0; ix <= poly->nX; ix++) { 2306 for (int iy = 0; iy <= poly->nY; iy++) { 2307 for (int iz = 0; iz <= poly->nZ; iz++) { 2308 if ((fabs(poly->coeff[ix][iy][iz] - polyOld->coeff[ix][iy][iz]) > FIT_TOLERANCE * fabs(poly->coeff[ix][iy][iz])) && 2309 (fabs(poly->coeff[ix][iy][iz] - polyOld->coeff[ix][iy][iz]) > FLT_TOLERANCE)) 2310 converged = false; 2311 } 2312 } 2313 } 2314 psFree (modErr); 2315 } 2316 2317 // Free local temporary variables 2318 psFree(x); 2319 psFree(y); 2320 psFree(z); 2321 psFree(polyOld); 2322 2323 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__); 2324 return true; 2325 } 2326 2327 /****************************************************************************** 2328 ****************************************************************************** 2329 4-D Vector Code. 2330 ****************************************************************************** 2331 *****************************************************************************/ 2332 /****************************************************************************** 2333 VectorFitPolynomial4DOrd(myPoly, *mask, maskValue, *f, *fErr, *x, *y, *z, *t): 2334 This is a private routine which will fit a 4-D polynomial to a set of (x, 2335 y, z, t)-(f) pairs. All non-NULL vectors must be of type PS_TYPE_F64. 2336 2337 *****************************************************************************/ 2338 static bool VectorFitPolynomial4DOrd( 2339 psPolynomial4D* myPoly, 2340 const psVector* mask, 2341 psVectorMaskType maskValue, 2342 const psVector *f, 2343 const psVector *fErr, 2344 const psVector *x, 2345 const psVector *y, 2346 const psVector *z, 2347 const psVector *t) 2348 { 2349 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__); 2350 PS_ASSERT_POLY_NON_NULL(myPoly, false); 2351 PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, false); 2352 PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, false); 2353 PS_ASSERT_INT_NONNEGATIVE(myPoly->nZ, false); 2354 PS_ASSERT_INT_NONNEGATIVE(myPoly->nT, false); 2355 PS_ASSERT_VECTOR_NON_NULL(f, false); 2356 PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, false); 2357 if (fErr != NULL) { 2358 PS_ASSERT_VECTORS_SIZE_EQUAL(y, fErr, false); 2359 PS_ASSERT_VECTOR_TYPE(fErr, PS_TYPE_F64, false); 2360 } 2361 PS_ASSERT_VECTOR_NON_NULL(x, false); 2362 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, false); 2363 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 2364 PS_ASSERT_VECTOR_NON_NULL(y, false); 2365 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, false); 2366 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 2367 PS_ASSERT_VECTOR_NON_NULL(z, false); 2368 PS_ASSERT_VECTOR_TYPE(z, PS_TYPE_F64, false); 2369 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false); 2370 PS_ASSERT_VECTOR_NON_NULL(t, false); 2371 PS_ASSERT_VECTOR_TYPE(t, PS_TYPE_F64, false); 2372 PS_ASSERT_VECTORS_SIZE_EQUAL(f, t, false); 2373 if (mask) { 2374 PS_ASSERT_VECTORS_SIZE_EQUAL(y, mask, false); 2375 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 2376 } 2377 2378 2379 int nXterm = 1 + myPoly->nX; // Number of x terms 2380 int nYterm = 1 + myPoly->nY; // Number of y terms 2381 int nZterm = 1 + myPoly->nZ; // Number of z terms 2382 int nTterm = 1 + myPoly->nT; // Number of t terms 2383 int nTerm = nXterm * nYterm * nZterm * nTterm; // Total number of terms 2384 int nData = x->n; // Number of data points 2385 psImage *A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64); // Least-squares matrix 2386 psVector *B = psVectorAlloc(nTerm, PS_TYPE_F64); // Least-squares vector 2387 2388 // Initialize data structures. 2389 if (!psImageInit(A, 0.0) || !psVectorInit(B, 0.0)) { 2390 psError(PS_ERR_UNKNOWN, false, "Could initialize data structures A, B. Returning NULL.\n"); 2391 psFree(A); 2392 psFree(B); 2393 psTrace("psLib.math", 4, "---- %s() End ----\n", __func__); 2394 return false; 2395 } 2396 2397 // Dereference points for speed in the loop 2398 psF64 **matrix = A->data.F64; // Least-squares matrix 2399 psF64 *vector = B->data.F64; // Least-squares vector 2400 psF64 *xData = x->data.F64; // x 2401 psF64 *yData = y->data.F64; // y 2402 psF64 *zData = z->data.F64; // z 2403 psF64 *tData = t->data.F64; // t 2404 psF64 *fData = f->data.F64; // f 2405 psF64 *fErrData = NULL; // Error in f 2406 if (fErr) { 2407 fErrData = fErr->data.F64; 2408 } 2409 psVectorMaskType *dataMask = NULL; // Mask for data 2410 if (mask) { 2411 dataMask = mask->data.PS_TYPE_VECTOR_MASK_DATA; 2412 } 2413 psMaskType ****coeffMask = myPoly->coeffMask; // Mask for polynomial terms 2414 int nYZTterm = nYterm * nZterm * nTterm; // Multiplication of the numbers, for calculating the index 2415 int nZTterm = nZterm * nTterm; // Multiplication of the numbers, for calculating the index 2416 2417 // Build the B and A data structs. 2418 psF64 ****Sums = NULL; // Sums look like: 1, x, x^2, ... x^(2n+1), y, xy, x^2y, ... x^(2n+1)*y, ... 2419 for (int k = 0; k < nData; k++) { 2420 if (dataMask && dataMask[k] & maskValue) { 2421 continue; 2422 } 2423 2424 Sums = BuildSums4D(Sums, xData[k], yData[k], zData[k], tData[k], nXterm, nYterm, nZterm, nTterm); 2425 2426 double wt; 2427 if (fErr == NULL) { 2428 wt = 1.0; 2429 } else { 2430 // this filters fErr == 0 values 2431 wt = (fErr->data.F64[k] == 0.0) ? 0.0 : 1.0 / PS_SQR(fErrData[k]); 2432 } 2433 2434 for (int i = 0; i < nTerm; i++) { 2435 int ix = i / (nYZTterm); // x index 2436 int iy = (i % (nYZTterm)) / (nZTterm); // y index 2437 int iz = ((i % (nYZTterm)) % (nZTterm)) / nTterm; // z index 2438 int it = ((i % (nYZTterm)) % (nZTterm)) % nTterm; // t index 2439 if (coeffMask[ix][iy][iz][it] & PS_POLY_MASK_BOTH) { 2440 matrix[i][i] = 1.0; 2441 continue; 2442 } 2443 2444 vector[i] += fData[k] * Sums[ix][iy][iz][it] * wt; 2445 matrix[i][i] += Sums[2*ix][2*iy][2*iz][2*it] * wt; 2446 for (int j = i + 1; j < nTerm; j++) { 2447 int jx = j / nYZTterm; // x index 2448 int jy = (j % nYZTterm) / nZTterm; // y index 2449 int jz = ((j % nYZTterm) % nZTterm) / nTterm; // z index 2450 int jt = ((j % nYZTterm) % nZTterm) % nTterm; // t index 2451 if (coeffMask[jx][jy][jz][jt] & PS_POLY_MASK_BOTH) { 2452 continue; 2453 } 2454 double value = Sums[ix+jx][iy+jy][iz+jz][it+jt] * wt; 2455 matrix[i][j] += value; 2456 matrix[j][i] += value; 2457 } 2458 } 2459 } 2460 2461 // Free the sums 2462 if (Sums == NULL) { 2463 assert (nData == 0); 2464 } else { 2465 for (int ix = 0; ix < 2*nXterm; ix++) { 2466 for (int iy = 0; iy < 2*nYterm; iy++) { 2467 for (int iz = 0; iz < 2*nZterm; iz++) { 2468 psFree(Sums[ix][iy][iz]); 2469 } 2470 psFree(Sums[ix][iy]); 2471 } 2472 psFree(Sums[ix]); 2473 } 2474 psFree(Sums); 2475 } 2476 2477 bool status = false; 2478 if (USE_GAUSS_JORDAN) { 2479 status = psMatrixGJSolve(A, B); 2480 } else { 2481 status = psMatrixLUSolve(A, B); 2482 } 2483 if (!status) { 2484 psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n"); 2485 goto escape; 2486 } 2487 2488 // select the appropriate solution entries 2489 for (int i = 0; i < nTerm; i++) { 2490 int ix = i / nYZTterm; // x index 2491 int iy = (i % nYZTterm) / nZTterm; // y index 2492 int iz = ((i % nYZTterm) % nZTterm) / nTterm; // z index 2493 int it = ((i % nYZTterm) % nZTterm) % nTterm; // t index 2494 if (coeffMask[ix][iy][iz][it] & PS_POLY_MASK_FIT) continue; 2495 myPoly->coeff[ix][iy][iz][it] = B->data.F64[i]; 2496 myPoly->coeffErr[ix][iy][iz][it] = sqrt(A->data.F64[i][i]); 2497 } 2498 psFree(A); 2499 psFree(B); 2500 return true; 2501 2502 escape: 2503 psFree(A); 2504 psFree(B); 2505 return false; 2506 } 2507 2508 /****************************************************************************** 2509 psVectorFitPolynomial4D(): This routine fits a 4D polynomial of arbitrary 2510 degree (specified in poly) to the data points (x, y, z, t)-(f) and returns 2511 that polynomial. Types F32 and F64 are supported, however, type F32 is done 2512 via vector conversion only. 2513 *****************************************************************************/ 2514 bool psVectorFitPolynomial4D( 2515 psPolynomial4D *poly, 2516 const psVector *mask, 2517 psVectorMaskType maskValue, 2518 const psVector *f, 2519 const psVector *fErr, 2520 const psVector *x, 2521 const psVector *y, 2522 const psVector *z, 2523 const psVector *t) 2524 { 2525 PS_ASSERT_POLY_NON_NULL(poly, false); 2526 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false); 2527 2528 PS_ASSERT_VECTOR_NON_NULL(f, false); 2529 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 2530 PS_ASSERT_VECTOR_NON_NULL(x, false); 2531 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 2532 PS_ASSERT_VECTOR_NON_NULL(y, false); 2533 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 2534 PS_ASSERT_VECTOR_NON_NULL(z, false); 2535 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false); 2536 PS_ASSERT_VECTOR_NON_NULL(t, false); 2537 PS_ASSERT_VECTORS_SIZE_EQUAL(f, t, false); 2538 if (mask) { 2539 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false); 2540 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 2541 } 2542 if (fErr != NULL) { 2543 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false); 2544 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(fErr, false); 2545 } 2546 2547 // Convert input vectors to F64 if necessary. 2548 psVector *f64 = (f->type.type == PS_TYPE_F64) ? (psVector *) f : psVectorCopy(NULL, f, PS_TYPE_F64); 2549 psVector *x64 = (x->type.type == PS_TYPE_F64) ? (psVector *) x : psVectorCopy(NULL, x, PS_TYPE_F64); 2550 psVector *y64 = (y->type.type == PS_TYPE_F64) ? (psVector *) y : psVectorCopy(NULL, y, PS_TYPE_F64); 2551 psVector *z64 = (z->type.type == PS_TYPE_F64) ? (psVector *) z : psVectorCopy(NULL, z, PS_TYPE_F64); 2552 psVector *t64 = (t->type.type == PS_TYPE_F64) ? (psVector *) t : psVectorCopy(NULL, t, PS_TYPE_F64); 2553 2554 psVector *fErr64 = NULL; 2555 if (fErr != NULL) { 2556 fErr64 = (fErr->type.type == PS_TYPE_F64) ? (psVector *) fErr : psVectorCopy(NULL, fErr, PS_TYPE_F64); 2557 } 2558 2559 bool result = true; 2560 2561 switch (poly->type) { 2562 case PS_POLYNOMIAL_ORD: 2563 result = VectorFitPolynomial4DOrd(poly, mask, maskValue, f64, fErr64, x64, y64, z64, t64); 2564 if (!result) { 2565 psError(PS_ERR_UNKNOWN, true, "Could not fit polynomial. Returning NULL.\n"); 2566 } 2567 break; 2568 case PS_POLYNOMIAL_CHEB: 2569 if (mask != NULL) { 2570 psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring mask and maskValue with Chebyshev polynomials.\n"); 2571 } 2572 psError(PS_ERR_UNKNOWN, true, "4-D Chebyshev polynomial vector fitting has not been implemented. Returning NULL.\n"); 2573 result = false; 2574 break; 2575 default: 2576 psError(PS_ERR_UNKNOWN, true, "Incorrect polynomial type. Returning NULL.\n"); 2577 result = false; 2578 break; 2579 } 2580 2581 // Free psVectors that were created for NULL arguments. 2582 PS_FREE_TEMP_F64_VECTOR (f, f64); 2583 PS_FREE_TEMP_F64_VECTOR (x, x64); 2584 PS_FREE_TEMP_F64_VECTOR (y, y64); 2585 PS_FREE_TEMP_F64_VECTOR (z, z64); 2586 PS_FREE_TEMP_F64_VECTOR (t, t64); 2587 PS_FREE_TEMP_F64_VECTOR (fErr, fErr64); 2588 2589 return result; 2590 } 2591 2592 2593 bool psVectorClipFitPolynomial4D( 2594 psPolynomial4D *poly, 2595 psStats *stats, 2596 const psVector *mask, 2597 psVectorMaskType maskValue, 2598 const psVector *f, 2599 const psVector *fErr, 2600 const psVector *x, 2601 const psVector *y, 2602 const psVector *z, 2603 const psVector *t) 2604 { 2605 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__); 2606 PS_ASSERT_POLY_NON_NULL(poly, false); 2607 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false); 2608 PS_ASSERT_PTR_NON_NULL(stats, false); 2609 PS_ASSERT_VECTOR_NON_NULL(mask, false); 2610 PS_ASSERT_VECTOR_NON_NULL(f, false); 2611 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 2612 2613 PS_ASSERT_VECTOR_NON_NULL(x, false); 2614 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false); 2615 PS_ASSERT_VECTOR_TYPE(x, f->type.type, false); 2616 2617 PS_ASSERT_VECTOR_NON_NULL(y, false); 2618 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false); 2619 PS_ASSERT_VECTOR_TYPE(y, f->type.type, false); 2620 2621 PS_ASSERT_VECTOR_NON_NULL(z, false); 2622 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false); 2623 PS_ASSERT_VECTOR_TYPE(z, f->type.type, false); 2624 2625 PS_ASSERT_VECTOR_NON_NULL(t, false); 2626 PS_ASSERT_VECTORS_SIZE_EQUAL(f, t, false); 2627 PS_ASSERT_VECTOR_TYPE(t, f->type.type, false); 2628 2629 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false); 2630 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 2631 2632 if (fErr != NULL) { 2633 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false); 2634 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false); 2635 } 2636 2637 // the user supplies one of various stats option pairs, 2638 // determine the desired mean and stdev STATS options: 2639 // XXX enforce consistency? 2640 // XXX psStatsGetValue() probably has inverted precedence 2641 psStatsOptions meanOption = stats->options & (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN | PS_STAT_ROBUST_MEDIAN | PS_STAT_CLIPPED_MEAN | PS_STAT_FITTED_MEAN | PS_STAT_FITTED_MEAN); 2642 psStatsOptions stdevOption = stats->options & (PS_STAT_SAMPLE_STDEV | PS_STAT_ROBUST_STDEV | PS_STAT_CLIPPED_STDEV | PS_STAT_FITTED_STDEV | PS_STAT_FITTED_STDEV); 2643 if (!meanOption) { 2644 psError(PS_ERR_UNKNOWN, true, "no valid mean stats option selected"); 2645 return false; 2646 } 2647 if (!stdevOption) { 2648 psError(PS_ERR_UNKNOWN, true, "no valid stdev stats option selected"); 2649 return false; 2650 } 2651 2652 // clipping range defined by min and max and/or clipSigma 2653 psF32 minClipSigma; 2654 psF32 maxClipSigma; 2655 if (isfinite(stats->max)) { 2656 maxClipSigma = fabs(stats->max); 2657 } else { 2658 maxClipSigma = fabs(stats->clipSigma); 2659 } 2660 if (isfinite(stats->min)) { 2661 minClipSigma = fabs(stats->min); 2662 } else { 2663 minClipSigma = fabs(stats->clipSigma); 2664 } 2665 psVector *resid = psVectorAlloc(f->n, PS_TYPE_F64); 2666 2667 psTrace("psLib.math", 4, "stats->clipIter is %d\n", stats->clipIter); 2668 psTrace("psLib.math", 4, "(minClipSigma, maxClipSigma) is (%.2f, %.2f)\n", minClipSigma, maxClipSigma); 2669 2670 for (psS32 N = 0; N < stats->clipIter; N++) { 2671 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial4D()\n", N); 2672 psS32 Nkeep = 0; 2673 if (psTraceGetLevel("psLib.math") >= 6) { 2674 if (mask != NULL) { 2675 for (psS32 i = 0 ; i < mask->n ; i++) { 2676 psTrace("psLib.math", 6, "mask[%d] is %d\n", i, mask->data.PS_TYPE_VECTOR_MASK_DATA[i]); 2677 } 2678 } 2679 } 2680 2681 if (!psVectorFitPolynomial4D (poly, mask, maskValue, f, fErr, x, y, z, t)) { 2682 psError(PS_ERR_UNKNOWN, false, "Could not fit a polynomial to the data. Returning NULL.\n"); 2683 psFree(resid); 2684 return false; 2685 } 2686 2687 psVector *fit = psPolynomial4DEvalVector (poly, x, y, z, t); 2688 if (fit == NULL) { 2689 psError(PS_ERR_UNKNOWN, false, "Could not call psPolynomial4DEvalVector(). Returning NULL.\n"); 2690 psFree(resid); 2691 return false; 2692 } 2693 for (psS32 i = 0 ; i < f->n ; i++) { 2694 if (f->type.type == PS_TYPE_F64) { 2695 resid->data.F64[i] = f->data.F64[i] - fit->data.F64[i]; 2696 } else { 2697 resid->data.F64[i] = ((psF64) f->data.F32[i]) - fit->data.F64[i]; 2698 } 2699 } 2700 2701 if (psTraceGetLevel("psLib.math") >= 6) { 2702 if (mask != NULL) { 2703 for (psS32 i = 0 ; i < mask->n ; i++) { 2704 if (!((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue))) { 2705 psTrace("psLib.math", 6, "(f, fit)[%d] is (%f, %f). resid is (%f)\n", 2706 i, f->data.F32[i], fit->data.F32[i], resid->data.F64[i]); 2707 } 2708 } 2709 } 2710 } 2711 2712 if (!psVectorStats(stats, resid, NULL, mask, maskValue)) { 2713 psError(PS_ERR_UNKNOWN, false, "Could not compute statistics on the resid vector. Returning NULL.\n"); 2714 psFree(resid); 2715 psFree(fit); 2716 return false; 2717 } 2718 2719 double meanValue = psStatsGetValue (stats, meanOption); 2720 double stdevValue = psStatsGetValue (stats, stdevOption); 2721 2722 psTrace("psLib.math", 5, "Mean is %f\n", meanValue); 2723 psTrace("psLib.math", 5, "Stdev is %f\n", stdevValue); 2724 psF32 minClipValue = -minClipSigma*stdevValue; 2725 psF32 maxClipValue = +maxClipSigma*stdevValue; 2726 2727 // set mask if pts are not valid 2728 // we are masking out any point which is out of range 2729 // recovery is not allowed with this scheme 2730 for (psS32 i = 0; i < resid->n; i++) { 2731 if ((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) { 2732 continue; 2733 } 2734 2735 if ((resid->data.F64[i] - meanValue > maxClipValue) || (resid->data.F64[i] - meanValue < minClipValue)) { 2736 if (f->type.type == PS_TYPE_F64) { 2737 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n", 2738 i, fit->data.F64[i], i, resid->data.F64[i]); 2739 } else { 2740 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n", 2741 i, fit->data.F32[i], i, resid->data.F64[i]); 2742 } 2743 2744 if (mask != NULL) { 2745 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= 0x01; 2746 } 2747 continue; 2748 } 2749 Nkeep++; 2750 } 2751 psTrace("psLib.math", 6, "keeping %d of %ld pts for fit\n", Nkeep, x->n); 2752 stats->clippedNvalues = Nkeep; 2753 psFree (fit); 2754 } 2755 // Free local temporary variables 2756 psFree (resid); 2757 2758 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__); 2759 return true; 2760 } 2761 2762 // This function accepts F32 and F64 input vectors. 2763 bool psVectorIRLSFitPolynomial4D( 2764 psPolynomial4D *poly, 2765 psStats *stats, 2766 const psVector *mask, 2767 psVectorMaskType maskValue, 2768 const psVector *f, 2769 const psVector *fErr, 2770 const psVector *xIn, 2771 const psVector *yIn, 2772 const psVector *zIn, 2773 const psVector *tIn) 2774 { 2775 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__); 2776 2777 PS_ASSERT (poly->type == PS_POLYNOMIAL_ORD, false); // XXX for now, only allow ORD 2778 PS_ASSERT_POLY_NON_NULL(poly, false); 2779 PS_ASSERT_VECTOR_NON_NULL(f, false); 2780 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false); 2781 if (mask != NULL) { 2782 PS_ASSERT_VECTORS_SIZE_EQUAL(mask, f, false); 2783 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 2784 } 2785 if (fErr != NULL) { 2786 PS_ASSERT_VECTORS_SIZE_EQUAL(fErr, f, false); 2787 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false); 2788 } 2789 if (xIn != NULL) { 2790 PS_ASSERT_VECTORS_SIZE_EQUAL(xIn, f, false); 2791 PS_ASSERT_VECTOR_TYPE(xIn, f->type.type, false); 2792 } 2793 if (yIn != NULL) { 2794 PS_ASSERT_VECTORS_SIZE_EQUAL(yIn, f, false); 2795 PS_ASSERT_VECTOR_TYPE(yIn, f->type.type, false); 2796 } 2797 if (zIn != NULL) { 2798 PS_ASSERT_VECTORS_SIZE_EQUAL(zIn, f, false); 2799 PS_ASSERT_VECTOR_TYPE(zIn, f->type.type, false); 2800 } 2801 if (tIn != NULL) { 2802 PS_ASSERT_VECTORS_SIZE_EQUAL(tIn, f, false); 2803 PS_ASSERT_VECTOR_TYPE(tIn, f->type.type, false); 2804 } 2805 2806 // Internal pointers for possibly NULL vectors. 2807 psVector *x = (xIn != NULL) ? psMemIncrRefCounter((psVector *) xIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 2808 psVector *y = (yIn != NULL) ? psMemIncrRefCounter((psVector *) yIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 2809 psVector *z = (zIn != NULL) ? psMemIncrRefCounter((psVector *) zIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 2810 psVector *t = (tIn != NULL) ? psMemIncrRefCounter((psVector *) tIn) : psVectorCreate(NULL, 0, f->n, 1, f->type.type); 2811 2812 // initial fit with nominal errors 2813 if (!psVectorFitPolynomial4D(poly, mask, maskValue, f, fErr, x, y, z, t)) { 2814 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 2815 psFree(x); 2816 psFree(y); 2817 psFree(z); 2818 psFree(t); 2819 return false; 2820 } 2821 2822 // use polyOld to save the last fit 2823 psPolynomial4D *polyOld = NULL; 2824 2825 // use clipIter as max number of iterations 2826 bool converged = false; 2827 for (psS32 N = 0; !converged && (N < stats->clipIter); N++) { 2828 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial4D()\n", N); 2829 2830 // evaluate the fit at the input positions 2831 psVector *fEval = psPolynomial4DEvalVector (poly, x, y, z, t); 2832 2833 // calculate modified errors based on the deviation from the fit 2834 psVector *modErr = psVector_GetModifiedErrors_Caucy (f, fEval, fErr, mask, maskValue); 2835 psFree (fEval); 2836 2837 // save the last fit (recycle the structure once allocated) 2838 polyOld = psPolynomial4DCopy (polyOld, poly); 2839 2840 // calculate a new fit with modified errors: 2841 if (!psVectorFitPolynomial4D(poly, mask, maskValue, f, modErr, x, y, z, t)) { 2842 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 2843 psFree(x); 2844 psFree(y); 2845 psFree(z); 2846 psFree(t); 2847 psFree(modErr); 2848 return false; 2849 } 2850 2851 // has the solution converged? 2852 converged = true; 2853 for (int ix = 0; ix <= poly->nX; ix++) { 2854 for (int iy = 0; iy <= poly->nY; iy++) { 2855 for (int iz = 0; iz <= poly->nZ; iz++) { 2856 for (int it = 0; it <= poly->nT; it++) { 2857 if ((fabs(poly->coeff[ix][iy][iz][it] - polyOld->coeff[ix][iy][iz][it]) > FIT_TOLERANCE * fabs(poly->coeff[ix][iy][iz][it])) && 2858 (fabs(poly->coeff[ix][iy][iz][it] - polyOld->coeff[ix][iy][iz][it]) > FLT_TOLERANCE)) 2859 converged = false; 2860 } 2861 } 2862 } 2863 } 2864 psFree (modErr); 2865 } 2866 2867 // Free local temporary variables 2868 psFree(x); 2869 psFree(y); 2870 psFree(z); 2871 psFree(t); 2872 psFree(polyOld); 2873 2874 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__); 2875 return true; 2876 } 2877 2878 // ######################## utilities ################### 2879 2880 // Used by IRLS fitting 1033 2881 // This function assumes the input vectors (f, fEval, fErr) all have the same type 1034 2882 // This requirement is already enforced in the calling function (psVectorIRLSFitPolynomial1D) … … 1078 2926 } 1079 2927 1080 // These should probably be tunable:1081 # define FIT_TOLERANCE 1e-41082 # define FLT_TOLERANCE 1e-61083 # define WEIGHT_THRESHOLD 0.31084 1085 // This function accepts F32 and F64 input vectors.1086 //1087 bool psVectorIRLSFitPolynomial1D(1088 psPolynomial1D *poly,1089 psStats *stats,1090 const psVector *mask,1091 psVectorMaskType maskValue,1092 const psVector *f,1093 const psVector *fErr,1094 const psVector *xIn)1095 {1096 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__);1097 PS_ASSERT_POLY_NON_NULL(poly, false);1098 PS_ASSERT_VECTOR_NON_NULL(f, false);1099 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false);1100 if (mask != NULL) {1101 PS_ASSERT_VECTORS_SIZE_EQUAL(mask, f, false);1102 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);1103 }1104 1105 if (fErr != NULL) {1106 PS_ASSERT_VECTORS_SIZE_EQUAL(fErr, f, false);1107 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false);1108 }1109 1110 // Internal pointers for possibly NULL vectors.1111 psVector *x = NULL;1112 if (xIn != NULL) {1113 PS_ASSERT_VECTORS_SIZE_EQUAL(xIn, f, false);1114 PS_ASSERT_VECTOR_TYPE(xIn, f->type.type, false);1115 x = (psVector *) xIn;1116 } else {1117 if (poly->type == PS_POLYNOMIAL_ORD) {1118 x = psVectorCreate(NULL, 0, f->n, 1, f->type.type);1119 } else if (poly->type == PS_POLYNOMIAL_CHEB) {1120 if (f->type.type == PS_TYPE_F32) {1121 PS_VECTOR_GEN_CHEBY_INDEX(x, f->n, PS_TYPE_F32);1122 } else if (f->type.type == PS_TYPE_F64) {1123 PS_VECTOR_GEN_CHEBY_INDEX(x, f->n, PS_TYPE_F64);1124 }1125 } else {1126 psError(PS_ERR_UNKNOWN, true, "Error, bad poly type.\n");1127 return false;1128 }1129 }1130 1131 // initial fit with nominal errors1132 if (!psVectorFitPolynomial1D(poly, mask, maskValue, f, fErr, x)) {1133 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n");1134 if (xIn == NULL) psFree(x);1135 return false;1136 }1137 1138 // use polyOld to save the last fit1139 psPolynomial1D *polyOld = NULL;1140 1141 // use clipIter as max number of iterations1142 bool converged = false;1143 for (psS32 N = 0; !converged && (N < stats->clipIter); N++) {1144 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial1D()\n", N);1145 1146 // evaluate the fit at the input positions1147 psVector *fEval = psPolynomial1DEvalVector (poly, x);1148 1149 // calculate modified errors based on the deviation from the fit1150 psVector *modErr = psVector_GetModifiedErrors_Caucy (f, fEval, fErr, mask, maskValue);1151 psFree (fEval);1152 1153 // save the last fit (recycle the structure once allocated)1154 polyOld = psPolynomial1DCopy (polyOld, poly);1155 1156 // calculate a new fit with modified errors:1157 if (!psVectorFitPolynomial1D(poly, mask, maskValue, f, modErr, x)) {1158 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n");1159 if (xIn == NULL) psFree(x);1160 psFree(modErr);1161 return false;1162 }1163 1164 // has the solution converged?1165 converged = true;1166 for (int ix = 0; ix <= poly->nX; ix++) {1167 if ((fabs(poly->coeff[ix] - polyOld->coeff[ix]) > FIT_TOLERANCE * fabs(poly->coeff[ix])) &&1168 (fabs(poly->coeff[ix] - polyOld->coeff[ix]) > FLT_TOLERANCE))1169 converged = false;1170 }1171 1172 # if (0)1173 // XXX test:1174 FILE *ftest = fopen ("irls.wt.dat", "w");1175 for (int i = 0; i < modErr->n; i++) {1176 if (modErr->type.type == PS_TYPE_F64) {1177 fprintf (ftest, "%d %f\n", i, modErr->data.F64[i]);1178 } else {1179 fprintf (ftest, "%d %f\n", i, modErr->data.F32[i]);1180 }1181 }1182 fclose (ftest);1183 # endif1184 psFree (modErr);1185 }1186 1187 // Free local temporary variables1188 if (xIn == NULL) psFree(x);1189 psFree(polyOld);1190 1191 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__);1192 return true;1193 }1194 1195 /******************************************************************************1196 ******************************************************************************1197 2-D Vector Code.1198 ******************************************************************************1199 *****************************************************************************/1200 1201 /******************************************************************************1202 VectorFitPolynomial2DOrd(myPoly, *mask, maskValue, *f, *fErr, *x, *y): This is1203 a private routine which will fit a 2-D polynomial to a set of (x, y)-(f)1204 pairs. All non-NULL vectors must be of type PS_TYPE_F64.1205 1206 *****************************************************************************/1207 static bool VectorFitPolynomial2DOrd(1208 psPolynomial2D* myPoly,1209 const psVector* mask,1210 psVectorMaskType maskValue,1211 const psVector *f,1212 const psVector *fErr,1213 const psVector *x,1214 const psVector *y)1215 {1216 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__);1217 PS_ASSERT_POLY_NON_NULL(myPoly, false);1218 PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, false);1219 PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, false);1220 PS_ASSERT_VECTOR_NON_NULL(f, false);1221 PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, false);1222 if (fErr != NULL) {1223 PS_ASSERT_VECTORS_SIZE_EQUAL(y, fErr, false);1224 PS_ASSERT_VECTOR_TYPE(fErr, PS_TYPE_F64, false);1225 }1226 PS_ASSERT_VECTOR_NON_NULL(x, false);1227 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, false);1228 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);1229 PS_ASSERT_VECTOR_NON_NULL(y, false);1230 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, false);1231 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);1232 if (mask != NULL) {1233 PS_ASSERT_VECTORS_SIZE_EQUAL(y, mask, false);1234 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);1235 }1236 1237 // Number of polynomial terms1238 int nXterm = 1 + myPoly->nX; // Number of terms in x1239 int nYterm = 1 + myPoly->nY; // Number of terms in y1240 int nTerm = nXterm * nYterm; // Total number of terms1241 1242 psImage *A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64); // Least-squares matrix1243 psVector *B = psVectorAlloc(nTerm, PS_TYPE_F64); // Least-squares vector1244 1245 // Initialize data structures.1246 if (!psImageInit(A, 0.0) || !psVectorInit(B, 0.0)) {1247 psError(PS_ERR_UNKNOWN, false, "Could initialize data structures A, B. Returning NULL.\n");1248 psFree(A);1249 psFree(B);1250 psTrace("psLib.math", 6, "---- %s() End ----\n", __func__);1251 return false;1252 }1253 1254 // Dereference stuff, to make the loop go faster1255 psF64 **matrix = A->data.F64; // Dereference the least-squares matrix1256 psF64 *vector = B->data.F64; // Dereference the least-squares vector1257 psMaskType **coeffMask = myPoly->coeffMask; // Dereference mask for polynomial terms1258 psVectorMaskType *dataMask = NULL; // Dereference mask for data1259 if (mask) {1260 dataMask = mask->data.PS_TYPE_VECTOR_MASK_DATA;1261 }1262 psF64 *xData = x->data.F64; // Dereference x1263 psF64 *yData = y->data.F64; // Dereference y1264 psF64 *fData = f->data.F64; // Dereference f1265 psF64 *fErrData = NULL; // Dereference fErr1266 if (fErr) {1267 fErrData = fErr->data.F64;1268 }1269 1270 // Build the least-squares matrix and vector1271 psImage *xySums = NULL; // The sums: 1, x, x^2, ... x^(2n+1), y, xy, x^2y, ... x^(2n+1)1272 for (int k = 0; k < x->n; k++) {1273 if (dataMask && dataMask[k] & maskValue) {1274 continue;1275 }1276 xySums = BuildSums2D(xySums, xData[k], yData[k], nXterm, nYterm);1277 psF64 **sums = xySums->data.F64;// Dereference sums1278 1279 double wt; // Weight1280 if (!fErrData) {1281 wt = 1.0;1282 } else {1283 // this filters fErr == 0 values1284 wt = (fErrData[k] == 0.0) ? 0.0 : 1.0 / PS_SQR(fErrData[k]);1285 }1286 1287 // Iterating over the matrix1288 for (int i = 0; i < nTerm; i++) {1289 int l = i / nYterm; // x index1290 int m = i % nYterm; // y index1291 if (coeffMask[l][m] & PS_POLY_MASK_SET) {1292 matrix[i][i] = 1.0;1293 continue;1294 }1295 vector[i] += fData[k] * sums[l][m] * wt;1296 matrix[i][i] += sums[2*l][2*m] * wt; // The diagonal entry1297 for (int j = i + 1; j < nTerm; j++) { // Doing the upper diagonal only: we will use symmetry1298 int p = j / nYterm; // x index1299 int q = j % nYterm; // y index1300 if (coeffMask[p][q] & PS_POLY_MASK_SET) {1301 continue;1302 }1303 double value = sums[l+p][m+q] * wt; // Value to add in1304 matrix[i][j] += value;1305 matrix[j][i] += value; // Taking advantage of the symmetry1306 }1307 }1308 }1309 psFree(xySums);1310 1311 // elements which are masked for fitting need to be subtracted from the vector1312 for (int i = 0; i < nTerm; i++) {1313 int ix = i / nYterm; // x index1314 int iy = i % nYterm; // y index1315 if (coeffMask[ix][iy] & PS_POLY_MASK_BOTH) {1316 continue;1317 }1318 for (int j = 0; j < nTerm; j++) { // The upper diagonal only: we will use symmetry1319 int jx = j / nYterm; // x index1320 int jy = j % nYterm; // y index1321 if (coeffMask[jx][jy] & PS_POLY_MASK_SET) {1322 continue;1323 }1324 if (!(coeffMask[jx][jy] & PS_POLY_MASK_FIT)) {1325 continue;1326 }1327 vector[i] -= matrix[i][j]*myPoly->coeff[jx][jy];1328 }1329 }1330 1331 // set the un-fitted and un-set elements to 0 or 1 for pivots1332 for (int i = 0; i < nTerm; i++) {1333 int ix = i / nYterm; // x index1334 int iy = i % nYterm; // y index1335 if (coeffMask[ix][iy] & PS_POLY_MASK_BOTH) {1336 for (int j = 0; j < nTerm; j++) { // The upper diagonal only: we will use symmetry1337 matrix[i][j] = 0.0;1338 matrix[j][i] = 0.0;1339 }1340 matrix[i][i] = 1.0;1341 continue;1342 }1343 }1344 1345 if (psTraceGetLevel("psLib.math") >= 4) {1346 printf("Least-squares vector:\n");1347 for (int i = 0; i < nTerm; i++) {1348 printf("%f ", B->data.F64[i]);1349 }1350 printf("\n");1351 printf("Least-squares matrix:\n");1352 for (int i = 0; i < nTerm; i++) {1353 for (int j = 0; j < nTerm; j++) {1354 printf("%f ", A->data.F64[i][j]);1355 }1356 printf("\n");1357 }1358 }1359 1360 bool status = false;1361 if (USE_GAUSS_JORDAN) {1362 status = psMatrixGJSolve(A, B);1363 } else {1364 status = psMatrixLUSolve(A, B);1365 }1366 if (!status) {1367 psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n");1368 goto escape;1369 }1370 1371 // select the appropriate solution entries (retain the incoming values if masked on the fit)1372 for (int i = 0; i < nTerm; i++) {1373 int ix = i / nYterm; // x index1374 int iy = i % nYterm; // y index1375 if (coeffMask[ix][iy] & PS_POLY_MASK_FIT) continue;1376 myPoly->coeff[ix][iy] = B->data.F64[i];1377 myPoly->coeffErr[ix][iy] = sqrt(A->data.F64[i][i]);1378 }1379 psFree(A);1380 psFree(B);1381 return true;1382 1383 escape:1384 psFree (A);1385 psFree (B);1386 return false;1387 }1388 1389 /******************************************************************************1390 VectorFitPolynomial2DCheb(myPoly, *mask, maskValue, *f, *fErr, *x, *y): This is1391 a private routine which will fit a 2-D polynomial to a set of (x, y)-(f)1392 pairs. All non-NULL vectors must be of type PS_TYPE_F64.1393 1394 *****************************************************************************/1395 static bool VectorFitPolynomial2DCheb(1396 psPolynomial2D* myPoly,1397 const psVector *f,1398 const psVector *x,1399 const psVector *y)1400 {1401 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__);1402 PS_ASSERT_POLY_NON_NULL(myPoly, false);1403 PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, false);1404 PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, false);1405 PS_ASSERT_VECTOR_NON_NULL(f, false);1406 PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, false);1407 PS_ASSERT_VECTOR_NON_NULL(x, false);1408 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, false);1409 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);1410 PS_ASSERT_VECTOR_NON_NULL(y, false);1411 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, false);1412 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);1413 1414 // Number of polynomial terms1415 int nXterm = 1 + myPoly->nX; // Number of terms in x1416 int nYterm = 1 + myPoly->nY; // Number of terms in y1417 int nTerm = nXterm * nYterm; // Total number of terms1418 if (nXterm > 9) {1419 psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit: orders higher than 9 are not yet coded\n");1420 return false;1421 }1422 if (nYterm > 9) {1423 psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit: orders higher than 9 are not yet coded\n");1424 return false;1425 }1426 1427 // determine scale factors1428 if (!psChebyshevSetScale (myPoly, x, 0)) { psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit.\n"); return false; }1429 if (!psChebyshevSetScale (myPoly, y, 1)) { psError(PS_ERR_UNKNOWN, false, "failed 2D chebyshev fit.\n"); return false; }1430 1431 // generate normalized vectors1432 psVector *xNorm = psChebyshevNormVector (myPoly, x, 0);1433 psVector *yNorm = psChebyshevNormVector (myPoly, y, 1);1434 1435 // generate the N cheb polynomials based on xNorm, yNorm1436 psArray *xPolySet = psArrayAlloc (nXterm);1437 for (int i = 0; i < nXterm; i++) {1438 xPolySet->data[i] = psChebyshevPolyVector (xNorm, i);1439 }1440 psArray *yPolySet = psArrayAlloc (nYterm);1441 for (int i = 0; i < nYterm; i++) {1442 yPolySet->data[i] = psChebyshevPolyVector (yNorm, i);1443 }1444 1445 psF64 *fData = f->data.F64; // Dereference f1446 1447 psImage *A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64); // Least-squares matrix1448 psVector *B = psVectorAlloc(nTerm, PS_TYPE_F64); // Least-squares vector1449 1450 // Initialize data structures (should not be able to fail)1451 psAssert (psImageInit(A, 0.0), "Could initialize data structures A");1452 psAssert (psVectorInit(B, 0.0), "Could initialize data structures B");1453 1454 // Dereference stuff, to make the loop go faster1455 psF64 **matrix = A->data.F64; // Dereference the least-squares matrix1456 psF64 *vector = B->data.F64; // Dereference the least-squares vector1457 1458 // loop over all elements of the data vector1459 for (int k = 0; k < x->n; k++) {1460 1461 if (!finite(fData[k])) continue;1462 1463 // XXX can we only calculate the upper diagonal?1464 int nelem = 0;1465 for (int jx = 0; jx < nXterm; jx++) {1466 psVector *jxCheb = xPolySet->data[jx];1467 for (int jy = 0; jy < nYterm; jy++) {1468 psVector *jyCheb = yPolySet->data[jy];1469 psF64 chebValue = jxCheb->data.F64[k] * jyCheb->data.F64[k];1470 1471 vector[nelem] += fData[k] * chebValue;1472 1473 int melem = 0;1474 for (int kx = 0; kx < nXterm; kx++) {1475 psVector *kxCheb = xPolySet->data[kx];1476 for (int ky = 0; ky < nYterm; ky++) {1477 psVector *kyCheb = yPolySet->data[ky];1478 matrix[nelem][melem] += chebValue * kxCheb->data.F64[k]*kyCheb->data.F64[k];1479 melem++;1480 }1481 }1482 nelem++;1483 }1484 }1485 }1486 1487 if (psTraceGetLevel("psLib.math") >= 4) {1488 printf("Least-squares vector:\n");1489 for (int i = 0; i < nTerm; i++) {1490 printf("%f ", B->data.F64[i]);1491 }1492 printf("\n");1493 printf("Least-squares matrix:\n");1494 for (int i = 0; i < nTerm; i++) {1495 for (int j = 0; j < nTerm; j++) {1496 printf("%f ", A->data.F64[i][j]);1497 }1498 printf("\n");1499 }1500 }1501 1502 bool status = false;1503 if (USE_GAUSS_JORDAN) {1504 status = psMatrixGJSolve(A, B);1505 } else {1506 status = psMatrixLUSolve(A, B);1507 }1508 if (!status) {1509 psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n");1510 goto escape;1511 }1512 1513 // unroll the result:1514 int nelem = 0;1515 for (int jx = 0; jx < nXterm; jx++) {1516 for (int jy = 0; jy < nYterm; jy++) {1517 myPoly->coeff[jx][jy] = B->data.F64[nelem];1518 myPoly->coeffErr[jx][jy] = sqrt(A->data.F64[nelem][nelem]);1519 nelem ++;1520 }1521 }1522 psFree(A);1523 psFree(B);1524 1525 psFree (xNorm);1526 psFree (yNorm);1527 psFree (xPolySet);1528 psFree (yPolySet);1529 1530 return true;1531 1532 escape:1533 psFree (A);1534 psFree (B);1535 return false;1536 }1537 1538 /******************************************************************************1539 psVectorFitPolynomial2D(): This routine fits a 2D polynomial of arbitrary1540 degree (specified in poly) to the data points (x, y)-(f) and returns that1541 polynomial. Types F32 and F64 are supported, however, type F32 is done via1542 vector conversion only.1543 *****************************************************************************/1544 bool psVectorFitPolynomial2D(1545 psPolynomial2D *poly,1546 const psVector *mask,1547 psVectorMaskType maskValue,1548 const psVector *f,1549 const psVector *fErr,1550 const psVector *x,1551 const psVector *y)1552 {1553 PS_ASSERT_POLY_NON_NULL(poly, false);1554 // PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false);1555 1556 PS_ASSERT_VECTOR_NON_NULL(f, false);1557 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false);1558 PS_ASSERT_VECTOR_NON_NULL(x, false);1559 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);1560 PS_ASSERT_VECTOR_NON_NULL(y, false);1561 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);1562 if (mask != NULL) {1563 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false);1564 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);1565 }1566 if (fErr != NULL) {1567 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false);1568 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(fErr, false);1569 }1570 1571 // Convert input vectors to F64 if necessary.1572 psVector *f64 = (f->type.type == PS_TYPE_F64) ? (psVector *) f : psVectorCopy(NULL, f, PS_TYPE_F64);1573 psVector *x64 = (x->type.type == PS_TYPE_F64) ? (psVector *) x : psVectorCopy(NULL, x, PS_TYPE_F64);1574 psVector *y64 = (y->type.type == PS_TYPE_F64) ? (psVector *) y : psVectorCopy(NULL, y, PS_TYPE_F64);1575 1576 psVector *fErr64 = NULL;1577 if (fErr != NULL) {1578 fErr64 = (fErr->type.type == PS_TYPE_F64) ? (psVector *) fErr : psVectorCopy(NULL, fErr, PS_TYPE_F64);1579 }1580 1581 bool result = true;1582 1583 switch (poly->type) {1584 case PS_POLYNOMIAL_ORD:1585 result = VectorFitPolynomial2DOrd(poly, mask, maskValue, f64, fErr64, x64, y64);1586 if (!result) {1587 psError(PS_ERR_UNKNOWN, true, "Could not fit polynomial. Returning NULL.\n");1588 }1589 break;1590 case PS_POLYNOMIAL_CHEB:1591 if (mask != NULL) {1592 psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring mask and maskValue with Chebyshev polynomials.\n");1593 }1594 if (fErr != NULL) {1595 psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring error values for Chebyshev polynomials.\n");1596 }1597 result = VectorFitPolynomial2DCheb(poly, f64, x64, y64);1598 if (!result) {1599 psError(PS_ERR_UNKNOWN, true, "Could not fit polynomial. Returning NULL.\n");1600 }1601 break;1602 default:1603 psError(PS_ERR_UNKNOWN, true, "Incorrect polynomial type. Returning NULL.\n");1604 result = false;1605 break;1606 }1607 1608 // Free psVectors that were created for NULL arguments.1609 PS_FREE_TEMP_F64_VECTOR (f, f64);1610 PS_FREE_TEMP_F64_VECTOR (x, x64);1611 PS_FREE_TEMP_F64_VECTOR (y, y64);1612 PS_FREE_TEMP_F64_VECTOR (fErr, fErr64);1613 1614 return result;1615 }1616 1617 bool psVectorClipFitPolynomial2D(1618 psPolynomial2D *poly,1619 psStats *stats,1620 const psVector *mask,1621 psVectorMaskType maskValue,1622 const psVector *f,1623 const psVector *fErr,1624 const psVector *x,1625 const psVector *y)1626 {1627 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__);1628 PS_ASSERT_POLY_NON_NULL(poly, false);1629 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false);1630 PS_ASSERT_PTR_NON_NULL(stats, false);1631 PS_ASSERT_VECTOR_NON_NULL(mask, false);1632 PS_ASSERT_VECTOR_NON_NULL(f, false);1633 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false);1634 1635 PS_ASSERT_VECTOR_NON_NULL(x, false);1636 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);1637 PS_ASSERT_VECTOR_TYPE(x, f->type.type, false);1638 1639 PS_ASSERT_VECTOR_NON_NULL(y, false);1640 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);1641 PS_ASSERT_VECTOR_TYPE(y, f->type.type, false);1642 1643 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false);1644 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);1645 1646 if (fErr != NULL) {1647 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false);1648 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false);1649 }1650 1651 // the user supplies one of various stats option pairs,1652 // determine the desired mean and stdev STATS options:1653 // XXX enforce consistency?1654 // XXX psStatsGetValue() probably has inverted precedence1655 psStatsOptions meanOption = stats->options & (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN | PS_STAT_ROBUST_MEDIAN | PS_STAT_CLIPPED_MEAN | PS_STAT_FITTED_MEAN | PS_STAT_FITTED_MEAN);1656 psStatsOptions stdevOption = stats->options & (PS_STAT_SAMPLE_STDEV | PS_STAT_ROBUST_STDEV | PS_STAT_CLIPPED_STDEV | PS_STAT_FITTED_STDEV | PS_STAT_FITTED_STDEV);1657 if (!meanOption) {1658 psError(PS_ERR_UNKNOWN, true, "no valid mean stats option selected");1659 return false;1660 }1661 if (!stdevOption) {1662 psError(PS_ERR_UNKNOWN, true, "no valid stdev stats option selected");1663 return false;1664 }1665 1666 // clipping range defined by min and max and/or clipSigma1667 psF32 minClipSigma;1668 psF32 maxClipSigma;1669 if (isfinite(stats->max)) {1670 maxClipSigma = fabs(stats->max);1671 } else {1672 maxClipSigma = fabs(stats->clipSigma);1673 }1674 if (isfinite(stats->min)) {1675 minClipSigma = fabs(stats->min);1676 } else {1677 minClipSigma = fabs(stats->clipSigma);1678 }1679 psVector *resid = psVectorAlloc(f->n, PS_TYPE_F64);1680 1681 psTrace("psLib.math", 4, "stats->clipIter is %d\n", stats->clipIter);1682 psTrace("psLib.math", 4, "(minClipSigma, maxClipSigma) is (%.2f, %.2f)\n", minClipSigma, maxClipSigma);1683 1684 for (psS32 N = 0; N < stats->clipIter; N++) {1685 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial1D()\n", N);1686 psS32 Nkeep = 0;1687 if (psTraceGetLevel("psLib.math") >= 7) {1688 if (mask != NULL) {1689 for (psS32 i = 0 ; i < mask->n ; i++) {1690 psTrace("psLib.math", 7, "mask[%d] is %d\n", i, mask->data.PS_TYPE_VECTOR_MASK_DATA[i]);1691 }1692 }1693 }1694 1695 if (!psVectorFitPolynomial2D(poly, mask, maskValue, f, fErr, x, y)) {1696 psError(PS_ERR_UNKNOWN, false, "Could not fit a polynomial to the data. Returning false.\n");1697 psFree(resid);1698 return false;1699 }1700 1701 psVector *fit = psPolynomial2DEvalVector(poly, x, y);1702 if (fit == NULL) {1703 psError(PS_ERR_UNKNOWN, false, "Could not call psPolynomial3DEvalVector(). Returning NULL.\n");1704 psFree(resid);1705 return false;1706 }1707 1708 for (psS32 i = 0 ; i < f->n ; i++) {1709 if (f->type.type == PS_TYPE_F64) {1710 resid->data.F64[i] = f->data.F64[i] - fit->data.F64[i];1711 } else {1712 resid->data.F64[i] = (psF64) (f->data.F32[i] - fit->data.F32[i]);1713 }1714 }1715 1716 if (psTraceGetLevel("psLib.math") >= 7) {1717 if (mask != NULL) {1718 for (psS32 i = 0 ; i < mask->n ; i++) {1719 if (!((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue))) {1720 psTrace("psLib.math", 7, "point %d at %f %f : value, fit : %f %f resid: %f\n",1721 i, x->data.F32[i], y->data.F32[i], f->data.F32[i], fit->data.F32[i], resid->data.F64[i]);1722 }1723 }1724 }1725 }1726 1727 if (!psVectorStats(stats, resid, NULL, mask, maskValue)) {1728 psError(PS_ERR_UNKNOWN, false, "Could not compute statistics on the resid vector. Returning NULL.\n");1729 psFree(resid);1730 psFree(fit);1731 return false;1732 }1733 1734 double meanValue = psStatsGetValue (stats, meanOption);1735 double stdevValue = psStatsGetValue (stats, stdevOption);1736 1737 psTrace("psLib.math", 5, "Mean is %f\n", meanValue);1738 psTrace("psLib.math", 5, "Stdev is %f\n", stdevValue);1739 psF32 minClipValue = -minClipSigma*stdevValue;1740 psF32 maxClipValue = +maxClipSigma*stdevValue;1741 1742 // set mask if pts are not valid1743 // we are masking out any point which is out of range1744 // recovery is not allowed with this scheme1745 for (psS32 i = 0; i < resid->n; i++) {1746 if ((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) {1747 continue;1748 }1749 1750 if ((resid->data.F64[i] - meanValue > maxClipValue) || (resid->data.F64[i] - meanValue < minClipValue)) {1751 if (fit->type.type == PS_TYPE_F64) {1752 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n",1753 i, fit->data.F64[i], i, resid->data.F64[i]);1754 } else {1755 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n",1756 i, fit->data.F32[i], i, resid->data.F64[i]);1757 }1758 1759 if (mask != NULL) {1760 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= 0x01;1761 }1762 continue;1763 }1764 Nkeep++;1765 }1766 psTrace("psLib.math", 4, "keeping %d of %ld pts for fit\n", Nkeep, x->n);1767 stats->clippedNvalues = Nkeep;1768 psFree(fit);1769 }1770 // Free local temporary variables1771 psFree(resid);1772 1773 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__);1774 return true;1775 }1776 1777 1778 /******************************************************************************1779 ******************************************************************************1780 3-D Vector Code.1781 ******************************************************************************1782 *****************************************************************************/1783 1784 /******************************************************************************1785 VectorFitPolynomial3DOrd(myPoly, *mask, maskValue, *f, *fErr, *x, *y, *z):1786 This is a private routine which will fit a 3-D polynomial to a set of (x,1787 y, z)-(f) pairs. All non-NULL vectors must be of type PS_TYPE_F64.1788 1789 *****************************************************************************/1790 static bool VectorFitPolynomial3DOrd(1791 psPolynomial3D* myPoly,1792 const psVector* mask,1793 psVectorMaskType maskValue,1794 const psVector *f,1795 const psVector *fErr,1796 const psVector *x,1797 const psVector *y,1798 const psVector *z)1799 {1800 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__);1801 PS_ASSERT_POLY_NON_NULL(myPoly, false);1802 PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, false);1803 PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, false);1804 PS_ASSERT_INT_NONNEGATIVE(myPoly->nZ, false);1805 1806 PS_ASSERT_VECTOR_NON_NULL(f, false);1807 PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, false);1808 if (fErr != NULL) {1809 PS_ASSERT_VECTORS_SIZE_EQUAL(y, fErr, false);1810 PS_ASSERT_VECTOR_TYPE(fErr, PS_TYPE_F64, false);1811 }1812 PS_ASSERT_VECTOR_NON_NULL(x, false);1813 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, false);1814 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);1815 PS_ASSERT_VECTOR_NON_NULL(y, false);1816 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, false);1817 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);1818 PS_ASSERT_VECTOR_NON_NULL(z, false);1819 PS_ASSERT_VECTOR_TYPE(z, PS_TYPE_F64, false);1820 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false);1821 if (mask != NULL) {1822 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false);1823 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);1824 }1825 1826 int nXterm = 1 + myPoly->nX; // Number of x terms1827 int nYterm = 1 + myPoly->nY; // Number of y terms1828 int nZterm = 1 + myPoly->nZ; // Number of z terms1829 int nTerm = nXterm * nYterm * nZterm; // Total number of terms1830 int nData = x->n; // Number of data points1831 psImage *A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64); // Least-squares matrix1832 psVector *B = psVectorAlloc(nTerm, PS_TYPE_F64); // Least-squares vector1833 1834 // Initialize data structures.1835 if (!psImageInit(A, 0.0) || !psVectorInit(B, 0.0)) {1836 psError(PS_ERR_UNKNOWN, false, "Could initialize data structures A, B. Returning NULL.\n");1837 psFree(A);1838 psFree(B);1839 psTrace("psLib.math", 4, "---- %s() End ----\n", __func__);1840 return false;1841 }1842 1843 // Dereference points for speed in the loop1844 psF64 **matrix = A->data.F64; // Least-squares matrix1845 psF64 *vector = B->data.F64; // Least-squares vector1846 psF64 *xData = x->data.F64; // x1847 psF64 *yData = y->data.F64; // y1848 psF64 *zData = z->data.F64; // z1849 psF64 *fData = f->data.F64; // f1850 psF64 *fErrData = NULL; // Error in f1851 if (fErr) {1852 fErrData = fErr->data.F64;1853 }1854 psVectorMaskType *dataMask = NULL; // Mask for data1855 if (mask) {1856 dataMask = mask->data.PS_TYPE_VECTOR_MASK_DATA;1857 }1858 psMaskType ***coeffMask = myPoly->coeffMask; // Mask for polynomial terms1859 int nYZterm = nYterm * nZterm; // Multiplication of the numbers, to calculate the index1860 1861 // Build the B and A data structs.1862 psF64 ***Sums = NULL; // Sums look like: 1, x, x^2, ... x^(2n+1), y, xy, x^2y, ... x^(2n+1)*y, ...1863 for (int k = 0; k < nData; k++) {1864 if (dataMask && dataMask[k] & maskValue) {1865 continue;1866 }1867 1868 Sums = BuildSums3D(Sums, xData[k], yData[k], zData[k], nXterm, nYterm, nZterm);1869 1870 double wt;1871 if (fErr == NULL) {1872 wt = 1.0;1873 } else {1874 // this filters fErr == 0 values1875 wt = (fErr->data.F64[k] == 0.0) ? 0.0 : 1.0 / PS_SQR(fErrData[k]);1876 }1877 1878 for (int i = 0; i < nTerm; i++) {1879 int ix = i / nYZterm; // x index1880 int iy = (i % nYZterm) / nZterm; // y index1881 int iz = (i % nYZterm) % nZterm; // z index1882 if (coeffMask[ix][iy][iz] & PS_POLY_MASK_BOTH) {1883 matrix[i][i] = 1.0;1884 continue;1885 }1886 1887 vector[i] += fData[k] * Sums[ix][iy][iz] * wt;1888 matrix[i][i] += Sums[2*ix][2*iy][2*iz] * wt;1889 for (int j = i + 1; j < nTerm; j++) {1890 int jx = j / (nYZterm); // x index1891 int jy = (j % nYZterm) / nZterm; // y index1892 int jz = (j % nYZterm) % nZterm; // z index1893 if (coeffMask[jx][jy][jz] & PS_POLY_MASK_BOTH) {1894 continue;1895 }1896 double value = Sums[ix+jx][iy+jy][iz+jz] * wt;1897 matrix[i][j] += value;1898 matrix[j][i] += value;1899 }1900 }1901 }1902 1903 // Free the sums1904 for (psS32 ix = 0; ix < 2*nXterm; ix++) {1905 for (psS32 iy = 0; iy < 2*nYterm; iy++) {1906 psFree(Sums[ix][iy]);1907 }1908 psFree(Sums[ix]);1909 }1910 psFree(Sums);1911 1912 1913 bool status = false;1914 if (USE_GAUSS_JORDAN) {1915 status = psMatrixGJSolve(A, B);1916 } else {1917 status = psMatrixLUSolve(A, B);1918 }1919 if (!status) {1920 psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n");1921 goto escape;1922 }1923 1924 // select the appropriate solution entries1925 for (int i = 0; i < nTerm; i++) {1926 int ix = i / nYZterm; // x index1927 int iy = (i % nYZterm) / nZterm; // y index1928 int iz = (i % nYZterm) % nZterm; // z index1929 if (coeffMask[ix][iy][iz] & PS_POLY_MASK_FIT) continue;1930 myPoly->coeff[ix][iy][iz] = B->data.F64[i];1931 myPoly->coeffErr[ix][iy][iz] = sqrt(A->data.F64[i][i]);1932 }1933 psFree(A);1934 psFree(B);1935 return true;1936 1937 escape:1938 psFree(A);1939 psFree(B);1940 return false;1941 }1942 1943 /******************************************************************************1944 psVectorFitPolynomial3D(): This routine fits a 3D polynomial of arbitrary1945 degree (specified in poly) to the data points (x, y, z)-(f) and returns that1946 polynomial. Types F32 and F64 are supported, however, type F32 is done via1947 vector conversion only.1948 *****************************************************************************/1949 bool psVectorFitPolynomial3D(1950 psPolynomial3D *poly,1951 const psVector *mask,1952 psVectorMaskType maskValue,1953 const psVector *f,1954 const psVector *fErr,1955 const psVector *x,1956 const psVector *y,1957 const psVector *z)1958 {1959 PS_ASSERT_POLY_NON_NULL(poly, false);1960 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false);1961 1962 PS_ASSERT_VECTOR_NON_NULL(f, false);1963 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false);1964 PS_ASSERT_VECTOR_NON_NULL(x, false);1965 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);1966 PS_ASSERT_VECTOR_NON_NULL(y, false);1967 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);1968 PS_ASSERT_VECTOR_NON_NULL(z, false);1969 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false);1970 if (mask != NULL) {1971 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false);1972 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);1973 }1974 if (fErr != NULL) {1975 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false);1976 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(fErr, false);1977 }1978 1979 // Convert input vectors to F64 if necessary.1980 psVector *f64 = (f->type.type == PS_TYPE_F64) ? (psVector *) f : psVectorCopy(NULL, f, PS_TYPE_F64);1981 psVector *x64 = (x->type.type == PS_TYPE_F64) ? (psVector *) x : psVectorCopy(NULL, x, PS_TYPE_F64);1982 psVector *y64 = (y->type.type == PS_TYPE_F64) ? (psVector *) y : psVectorCopy(NULL, y, PS_TYPE_F64);1983 psVector *z64 = (z->type.type == PS_TYPE_F64) ? (psVector *) z : psVectorCopy(NULL, z, PS_TYPE_F64);1984 1985 psVector *fErr64 = NULL;1986 if (fErr != NULL) {1987 fErr64 = (fErr->type.type == PS_TYPE_F64) ? (psVector *) fErr : psVectorCopy(NULL, fErr, PS_TYPE_F64);1988 }1989 1990 bool result = true;1991 1992 switch (poly->type) {1993 case PS_POLYNOMIAL_ORD:1994 result = VectorFitPolynomial3DOrd(poly, mask, maskValue, f64, fErr64, x64, y64, z64);1995 if (!result) {1996 psError(PS_ERR_UNKNOWN, true, "Could not fit polynomial. Returning NULL.\n");1997 }1998 break;1999 case PS_POLYNOMIAL_CHEB:2000 if (mask != NULL) {2001 psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring mask and maskValue with Chebyshev polynomials.\n");2002 }2003 psError(PS_ERR_UNKNOWN, true, "3-D Chebyshev polynomial vector fitting has not been implemented. Returning NULL.\n");2004 result = false;2005 break;2006 default:2007 psError(PS_ERR_UNKNOWN, true, "Incorrect polynomial type. Returning NULL.\n");2008 result = false;2009 break;2010 }2011 2012 // Free psVectors that were created for NULL arguments.2013 PS_FREE_TEMP_F64_VECTOR (f, f64);2014 PS_FREE_TEMP_F64_VECTOR (x, x64);2015 PS_FREE_TEMP_F64_VECTOR (y, y64);2016 PS_FREE_TEMP_F64_VECTOR (z, z64);2017 PS_FREE_TEMP_F64_VECTOR (fErr, fErr64);2018 2019 return result;2020 }2021 2022 bool psVectorClipFitPolynomial3D(2023 psPolynomial3D *poly,2024 psStats *stats,2025 const psVector *mask,2026 psVectorMaskType maskValue,2027 const psVector *f,2028 const psVector *fErr,2029 const psVector *x,2030 const psVector *y,2031 const psVector *z)2032 {2033 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__);2034 PS_ASSERT_POLY_NON_NULL(poly, false);2035 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false);2036 PS_ASSERT_PTR_NON_NULL(stats, false);2037 PS_ASSERT_VECTOR_NON_NULL(mask, false);2038 PS_ASSERT_VECTOR_NON_NULL(f, false);2039 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false);2040 2041 PS_ASSERT_VECTOR_NON_NULL(x, false);2042 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);2043 PS_ASSERT_VECTOR_TYPE(x, f->type.type, false);2044 2045 PS_ASSERT_VECTOR_NON_NULL(y, false);2046 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);2047 PS_ASSERT_VECTOR_TYPE(y, f->type.type, false);2048 2049 PS_ASSERT_VECTOR_NON_NULL(z, false);2050 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false);2051 PS_ASSERT_VECTOR_TYPE(z, f->type.type, false);2052 2053 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false);2054 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);2055 2056 if (fErr != NULL) {2057 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false);2058 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false);2059 }2060 2061 // the user supplies one of various stats option pairs,2062 // determine the desired mean and stdev STATS options:2063 // XXX enforce consistency?2064 // XXX psStatsGetValue() probably has inverted precedence2065 psStatsOptions meanOption = stats->options & (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN | PS_STAT_ROBUST_MEDIAN | PS_STAT_CLIPPED_MEAN | PS_STAT_FITTED_MEAN | PS_STAT_FITTED_MEAN);2066 psStatsOptions stdevOption = stats->options & (PS_STAT_SAMPLE_STDEV | PS_STAT_ROBUST_STDEV | PS_STAT_CLIPPED_STDEV | PS_STAT_FITTED_STDEV | PS_STAT_FITTED_STDEV);2067 if (!meanOption) {2068 psError(PS_ERR_UNKNOWN, true, "no valid mean stats option selected");2069 return false;2070 }2071 if (!stdevOption) {2072 psError(PS_ERR_UNKNOWN, true, "no valid stdev stats option selected");2073 return false;2074 }2075 2076 // clipping range defined by min and max and/or clipSigma2077 psF32 minClipSigma;2078 psF32 maxClipSigma;2079 if (isfinite(stats->max)) {2080 maxClipSigma = fabs(stats->max);2081 } else {2082 maxClipSigma = fabs(stats->clipSigma);2083 }2084 if (isfinite(stats->min)) {2085 minClipSigma = fabs(stats->min);2086 } else {2087 minClipSigma = fabs(stats->clipSigma);2088 }2089 psVector *resid = psVectorAlloc(f->n, PS_TYPE_F64);2090 2091 psTrace("psLib.math", 4, "stats->clipIter is %d\n", stats->clipIter);2092 psTrace("psLib.math", 4, "(minClipSigma, maxClipSigma) is (%.2f, %.2f)\n", minClipSigma, maxClipSigma);2093 2094 for (psS32 N = 0; N < stats->clipIter; N++) {2095 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial1D()\n", N);2096 psS32 Nkeep = 0;2097 if (psTraceGetLevel("psLib.math") >= 6) {2098 if (mask != NULL) {2099 for (psS32 i = 0 ; i < mask->n ; i++) {2100 psTrace("psLib.math", 6, "mask[%d] is %d\n", i, mask->data.PS_TYPE_VECTOR_MASK_DATA[i]);2101 }2102 }2103 }2104 2105 if (!psVectorFitPolynomial3D(poly, mask, maskValue, f, fErr, x, y, z)) {2106 psError(PS_ERR_UNKNOWN, false, "Could not fit a polynomial to the data. Returning NULL.\n");2107 psFree(resid);2108 return false;2109 }2110 psVector *fit = psPolynomial3DEvalVector(poly, x, y, z);2111 if (fit == NULL) {2112 psError(PS_ERR_UNKNOWN, false, "Could not call psPolynomial3DEvalVector(). Returning NULL.\n");2113 psFree(resid);2114 return false;2115 }2116 for (psS32 i = 0 ; i < f->n ; i++) {2117 if (f->type.type == PS_TYPE_F64) {2118 resid->data.F64[i] = f->data.F64[i] - fit->data.F64[i];2119 } else {2120 resid->data.F64[i] = ((psF64) f->data.F32[i]) - fit->data.F64[i];2121 }2122 }2123 2124 if (psTraceGetLevel("psLib.math") >= 6) {2125 if (mask != NULL) {2126 for (psS32 i = 0 ; i < mask->n ; i++) {2127 if (!((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue))) {2128 psTrace("psLib.math", 6, "(f, fit)[%d] is (%f, %f). resid is (%f)\n",2129 i, f->data.F32[i], fit->data.F32[i], resid->data.F64[i]);2130 }2131 }2132 }2133 }2134 2135 if (!psVectorStats(stats, resid, NULL, mask, maskValue)) {2136 psError(PS_ERR_UNKNOWN, false, "Could not compute statistics on the resid vector. Returning NULL.\n");2137 psFree(resid);2138 psFree(fit);2139 return false;2140 }2141 2142 double meanValue = psStatsGetValue (stats, meanOption);2143 double stdevValue = psStatsGetValue (stats, stdevOption);2144 2145 psTrace("psLib.math", 5, "Mean is %f\n", meanValue);2146 psTrace("psLib.math", 5, "Stdev is %f\n", stdevValue);2147 psF32 minClipValue = -minClipSigma*stdevValue;2148 psF32 maxClipValue = +maxClipSigma*stdevValue;2149 2150 // set mask if pts are not valid2151 // we are masking out any point which is out of range2152 // recovery is not allowed with this scheme2153 for (psS32 i = 0; i < resid->n; i++) {2154 if ((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) {2155 continue;2156 }2157 2158 if ((resid->data.F64[i] - meanValue > maxClipValue) || (resid->data.F64[i] - meanValue < minClipValue)) {2159 if (f->type.type == PS_TYPE_F64) {2160 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n",2161 i, fit->data.F64[i], i, resid->data.F64[i]);2162 } else {2163 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n",2164 i, fit->data.F32[i], i, resid->data.F64[i]);2165 }2166 2167 if (mask != NULL) {2168 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= 0x01;2169 }2170 continue;2171 }2172 Nkeep++;2173 }2174 psTrace("psLib.math", 6, "keeping %d of %ld pts for fit\n", Nkeep, x->n);2175 stats->clippedNvalues = Nkeep;2176 psFree(fit);2177 }2178 // Free local temporary variables2179 psFree(resid);2180 2181 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__);2182 return true;2183 }2184 2185 /******************************************************************************2186 ******************************************************************************2187 4-D Vector Code.2188 ******************************************************************************2189 *****************************************************************************/2190 /******************************************************************************2191 VectorFitPolynomial4DOrd(myPoly, *mask, maskValue, *f, *fErr, *x, *y, *z, *t):2192 This is a private routine which will fit a 4-D polynomial to a set of (x,2193 y, z, t)-(f) pairs. All non-NULL vectors must be of type PS_TYPE_F64.2194 2195 *****************************************************************************/2196 static bool VectorFitPolynomial4DOrd(2197 psPolynomial4D* myPoly,2198 const psVector* mask,2199 psVectorMaskType maskValue,2200 const psVector *f,2201 const psVector *fErr,2202 const psVector *x,2203 const psVector *y,2204 const psVector *z,2205 const psVector *t)2206 {2207 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__);2208 PS_ASSERT_POLY_NON_NULL(myPoly, false);2209 PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, false);2210 PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, false);2211 PS_ASSERT_INT_NONNEGATIVE(myPoly->nZ, false);2212 PS_ASSERT_INT_NONNEGATIVE(myPoly->nT, false);2213 PS_ASSERT_VECTOR_NON_NULL(f, false);2214 PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, false);2215 if (fErr != NULL) {2216 PS_ASSERT_VECTORS_SIZE_EQUAL(y, fErr, false);2217 PS_ASSERT_VECTOR_TYPE(fErr, PS_TYPE_F64, false);2218 }2219 PS_ASSERT_VECTOR_NON_NULL(x, false);2220 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, false);2221 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);2222 PS_ASSERT_VECTOR_NON_NULL(y, false);2223 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, false);2224 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);2225 PS_ASSERT_VECTOR_NON_NULL(z, false);2226 PS_ASSERT_VECTOR_TYPE(z, PS_TYPE_F64, false);2227 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false);2228 PS_ASSERT_VECTOR_NON_NULL(t, false);2229 PS_ASSERT_VECTOR_TYPE(t, PS_TYPE_F64, false);2230 PS_ASSERT_VECTORS_SIZE_EQUAL(f, t, false);2231 if (mask) {2232 PS_ASSERT_VECTORS_SIZE_EQUAL(y, mask, false);2233 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);2234 }2235 2236 2237 int nXterm = 1 + myPoly->nX; // Number of x terms2238 int nYterm = 1 + myPoly->nY; // Number of y terms2239 int nZterm = 1 + myPoly->nZ; // Number of z terms2240 int nTterm = 1 + myPoly->nT; // Number of t terms2241 int nTerm = nXterm * nYterm * nZterm * nTterm; // Total number of terms2242 int nData = x->n; // Number of data points2243 psImage *A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64); // Least-squares matrix2244 psVector *B = psVectorAlloc(nTerm, PS_TYPE_F64); // Least-squares vector2245 2246 // Initialize data structures.2247 if (!psImageInit(A, 0.0) || !psVectorInit(B, 0.0)) {2248 psError(PS_ERR_UNKNOWN, false, "Could initialize data structures A, B. Returning NULL.\n");2249 psFree(A);2250 psFree(B);2251 psTrace("psLib.math", 4, "---- %s() End ----\n", __func__);2252 return false;2253 }2254 2255 // Dereference points for speed in the loop2256 psF64 **matrix = A->data.F64; // Least-squares matrix2257 psF64 *vector = B->data.F64; // Least-squares vector2258 psF64 *xData = x->data.F64; // x2259 psF64 *yData = y->data.F64; // y2260 psF64 *zData = z->data.F64; // z2261 psF64 *tData = t->data.F64; // t2262 psF64 *fData = f->data.F64; // f2263 psF64 *fErrData = NULL; // Error in f2264 if (fErr) {2265 fErrData = fErr->data.F64;2266 }2267 psVectorMaskType *dataMask = NULL; // Mask for data2268 if (mask) {2269 dataMask = mask->data.PS_TYPE_VECTOR_MASK_DATA;2270 }2271 psMaskType ****coeffMask = myPoly->coeffMask; // Mask for polynomial terms2272 int nYZTterm = nYterm * nZterm * nTterm; // Multiplication of the numbers, for calculating the index2273 int nZTterm = nZterm * nTterm; // Multiplication of the numbers, for calculating the index2274 2275 // Build the B and A data structs.2276 psF64 ****Sums = NULL; // Sums look like: 1, x, x^2, ... x^(2n+1), y, xy, x^2y, ... x^(2n+1)*y, ...2277 for (int k = 0; k < nData; k++) {2278 if (dataMask && dataMask[k] & maskValue) {2279 continue;2280 }2281 2282 Sums = BuildSums4D(Sums, xData[k], yData[k], zData[k], tData[k], nXterm, nYterm, nZterm, nTterm);2283 2284 double wt;2285 if (fErr == NULL) {2286 wt = 1.0;2287 } else {2288 // this filters fErr == 0 values2289 wt = (fErr->data.F64[k] == 0.0) ? 0.0 : 1.0 / PS_SQR(fErrData[k]);2290 }2291 2292 for (int i = 0; i < nTerm; i++) {2293 int ix = i / (nYZTterm); // x index2294 int iy = (i % (nYZTterm)) / (nZTterm); // y index2295 int iz = ((i % (nYZTterm)) % (nZTterm)) / nTterm; // z index2296 int it = ((i % (nYZTterm)) % (nZTterm)) % nTterm; // t index2297 if (coeffMask[ix][iy][iz][it] & PS_POLY_MASK_BOTH) {2298 matrix[i][i] = 1.0;2299 continue;2300 }2301 2302 vector[i] += fData[k] * Sums[ix][iy][iz][it] * wt;2303 matrix[i][i] += Sums[2*ix][2*iy][2*iz][2*it] * wt;2304 for (int j = i + 1; j < nTerm; j++) {2305 int jx = j / nYZTterm; // x index2306 int jy = (j % nYZTterm) / nZTterm; // y index2307 int jz = ((j % nYZTterm) % nZTterm) / nTterm; // z index2308 int jt = ((j % nYZTterm) % nZTterm) % nTterm; // t index2309 if (coeffMask[jx][jy][jz][jt] & PS_POLY_MASK_BOTH) {2310 continue;2311 }2312 double value = Sums[ix+jx][iy+jy][iz+jz][it+jt] * wt;2313 matrix[i][j] += value;2314 matrix[j][i] += value;2315 }2316 }2317 }2318 2319 // Free the sums2320 if (Sums == NULL) {2321 assert (nData == 0);2322 } else {2323 for (int ix = 0; ix < 2*nXterm; ix++) {2324 for (int iy = 0; iy < 2*nYterm; iy++) {2325 for (int iz = 0; iz < 2*nZterm; iz++) {2326 psFree(Sums[ix][iy][iz]);2327 }2328 psFree(Sums[ix][iy]);2329 }2330 psFree(Sums[ix]);2331 }2332 psFree(Sums);2333 }2334 2335 bool status = false;2336 if (USE_GAUSS_JORDAN) {2337 status = psMatrixGJSolve(A, B);2338 } else {2339 status = psMatrixLUSolve(A, B);2340 }2341 if (!status) {2342 psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n");2343 goto escape;2344 }2345 2346 // select the appropriate solution entries2347 for (int i = 0; i < nTerm; i++) {2348 int ix = i / nYZTterm; // x index2349 int iy = (i % nYZTterm) / nZTterm; // y index2350 int iz = ((i % nYZTterm) % nZTterm) / nTterm; // z index2351 int it = ((i % nYZTterm) % nZTterm) % nTterm; // t index2352 if (coeffMask[ix][iy][iz][it] & PS_POLY_MASK_FIT) continue;2353 myPoly->coeff[ix][iy][iz][it] = B->data.F64[i];2354 myPoly->coeffErr[ix][iy][iz][it] = sqrt(A->data.F64[i][i]);2355 }2356 psFree(A);2357 psFree(B);2358 return true;2359 2360 escape:2361 psFree(A);2362 psFree(B);2363 return false;2364 }2365 2366 /******************************************************************************2367 psVectorFitPolynomial4D(): This routine fits a 4D polynomial of arbitrary2368 degree (specified in poly) to the data points (x, y, z, t)-(f) and returns2369 that polynomial. Types F32 and F64 are supported, however, type F32 is done2370 via vector conversion only.2371 *****************************************************************************/2372 bool psVectorFitPolynomial4D(2373 psPolynomial4D *poly,2374 const psVector *mask,2375 psVectorMaskType maskValue,2376 const psVector *f,2377 const psVector *fErr,2378 const psVector *x,2379 const psVector *y,2380 const psVector *z,2381 const psVector *t)2382 {2383 PS_ASSERT_POLY_NON_NULL(poly, false);2384 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false);2385 2386 PS_ASSERT_VECTOR_NON_NULL(f, false);2387 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false);2388 PS_ASSERT_VECTOR_NON_NULL(x, false);2389 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);2390 PS_ASSERT_VECTOR_NON_NULL(y, false);2391 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);2392 PS_ASSERT_VECTOR_NON_NULL(z, false);2393 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false);2394 PS_ASSERT_VECTOR_NON_NULL(t, false);2395 PS_ASSERT_VECTORS_SIZE_EQUAL(f, t, false);2396 if (mask) {2397 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false);2398 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);2399 }2400 if (fErr != NULL) {2401 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false);2402 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(fErr, false);2403 }2404 2405 // Convert input vectors to F64 if necessary.2406 psVector *f64 = (f->type.type == PS_TYPE_F64) ? (psVector *) f : psVectorCopy(NULL, f, PS_TYPE_F64);2407 psVector *x64 = (x->type.type == PS_TYPE_F64) ? (psVector *) x : psVectorCopy(NULL, x, PS_TYPE_F64);2408 psVector *y64 = (y->type.type == PS_TYPE_F64) ? (psVector *) y : psVectorCopy(NULL, y, PS_TYPE_F64);2409 psVector *z64 = (z->type.type == PS_TYPE_F64) ? (psVector *) z : psVectorCopy(NULL, z, PS_TYPE_F64);2410 psVector *t64 = (t->type.type == PS_TYPE_F64) ? (psVector *) t : psVectorCopy(NULL, t, PS_TYPE_F64);2411 2412 psVector *fErr64 = NULL;2413 if (fErr != NULL) {2414 fErr64 = (fErr->type.type == PS_TYPE_F64) ? (psVector *) fErr : psVectorCopy(NULL, fErr, PS_TYPE_F64);2415 }2416 2417 bool result = true;2418 2419 switch (poly->type) {2420 case PS_POLYNOMIAL_ORD:2421 result = VectorFitPolynomial4DOrd(poly, mask, maskValue, f64, fErr64, x64, y64, z64, t64);2422 if (!result) {2423 psError(PS_ERR_UNKNOWN, true, "Could not fit polynomial. Returning NULL.\n");2424 }2425 break;2426 case PS_POLYNOMIAL_CHEB:2427 if (mask != NULL) {2428 psLogMsg(__func__, PS_LOG_WARN, "WARNING: ignoring mask and maskValue with Chebyshev polynomials.\n");2429 }2430 psError(PS_ERR_UNKNOWN, true, "4-D Chebyshev polynomial vector fitting has not been implemented. Returning NULL.\n");2431 result = false;2432 break;2433 default:2434 psError(PS_ERR_UNKNOWN, true, "Incorrect polynomial type. Returning NULL.\n");2435 result = false;2436 break;2437 }2438 2439 // Free psVectors that were created for NULL arguments.2440 PS_FREE_TEMP_F64_VECTOR (f, f64);2441 PS_FREE_TEMP_F64_VECTOR (x, x64);2442 PS_FREE_TEMP_F64_VECTOR (y, y64);2443 PS_FREE_TEMP_F64_VECTOR (z, z64);2444 PS_FREE_TEMP_F64_VECTOR (t, t64);2445 PS_FREE_TEMP_F64_VECTOR (fErr, fErr64);2446 2447 return result;2448 }2449 2450 2451 bool psVectorClipFitPolynomial4D(2452 psPolynomial4D *poly,2453 psStats *stats,2454 const psVector *mask,2455 psVectorMaskType maskValue,2456 const psVector *f,2457 const psVector *fErr,2458 const psVector *x,2459 const psVector *y,2460 const psVector *z,2461 const psVector *t)2462 {2463 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__);2464 PS_ASSERT_POLY_NON_NULL(poly, false);2465 PS_ASSERT_POLY_TYPE(poly, PS_POLYNOMIAL_ORD, false);2466 PS_ASSERT_PTR_NON_NULL(stats, false);2467 PS_ASSERT_VECTOR_NON_NULL(mask, false);2468 PS_ASSERT_VECTOR_NON_NULL(f, false);2469 PS_ASSERT_VECTOR_TYPE_F32_OR_F64(f, false);2470 2471 PS_ASSERT_VECTOR_NON_NULL(x, false);2472 PS_ASSERT_VECTORS_SIZE_EQUAL(f, x, false);2473 PS_ASSERT_VECTOR_TYPE(x, f->type.type, false);2474 2475 PS_ASSERT_VECTOR_NON_NULL(y, false);2476 PS_ASSERT_VECTORS_SIZE_EQUAL(f, y, false);2477 PS_ASSERT_VECTOR_TYPE(y, f->type.type, false);2478 2479 PS_ASSERT_VECTOR_NON_NULL(z, false);2480 PS_ASSERT_VECTORS_SIZE_EQUAL(f, z, false);2481 PS_ASSERT_VECTOR_TYPE(z, f->type.type, false);2482 2483 PS_ASSERT_VECTOR_NON_NULL(t, false);2484 PS_ASSERT_VECTORS_SIZE_EQUAL(f, t, false);2485 PS_ASSERT_VECTOR_TYPE(t, f->type.type, false);2486 2487 PS_ASSERT_VECTORS_SIZE_EQUAL(f, mask, false);2488 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false);2489 2490 if (fErr != NULL) {2491 PS_ASSERT_VECTORS_SIZE_EQUAL(f, fErr, false);2492 PS_ASSERT_VECTOR_TYPE(fErr, f->type.type, false);2493 }2494 2495 // the user supplies one of various stats option pairs,2496 // determine the desired mean and stdev STATS options:2497 // XXX enforce consistency?2498 // XXX psStatsGetValue() probably has inverted precedence2499 psStatsOptions meanOption = stats->options & (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN | PS_STAT_ROBUST_MEDIAN | PS_STAT_CLIPPED_MEAN | PS_STAT_FITTED_MEAN | PS_STAT_FITTED_MEAN);2500 psStatsOptions stdevOption = stats->options & (PS_STAT_SAMPLE_STDEV | PS_STAT_ROBUST_STDEV | PS_STAT_CLIPPED_STDEV | PS_STAT_FITTED_STDEV | PS_STAT_FITTED_STDEV);2501 if (!meanOption) {2502 psError(PS_ERR_UNKNOWN, true, "no valid mean stats option selected");2503 return false;2504 }2505 if (!stdevOption) {2506 psError(PS_ERR_UNKNOWN, true, "no valid stdev stats option selected");2507 return false;2508 }2509 2510 // clipping range defined by min and max and/or clipSigma2511 psF32 minClipSigma;2512 psF32 maxClipSigma;2513 if (isfinite(stats->max)) {2514 maxClipSigma = fabs(stats->max);2515 } else {2516 maxClipSigma = fabs(stats->clipSigma);2517 }2518 if (isfinite(stats->min)) {2519 minClipSigma = fabs(stats->min);2520 } else {2521 minClipSigma = fabs(stats->clipSigma);2522 }2523 psVector *resid = psVectorAlloc(f->n, PS_TYPE_F64);2524 2525 psTrace("psLib.math", 4, "stats->clipIter is %d\n", stats->clipIter);2526 psTrace("psLib.math", 4, "(minClipSigma, maxClipSigma) is (%.2f, %.2f)\n", minClipSigma, maxClipSigma);2527 2528 for (psS32 N = 0; N < stats->clipIter; N++) {2529 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial4D()\n", N);2530 psS32 Nkeep = 0;2531 if (psTraceGetLevel("psLib.math") >= 6) {2532 if (mask != NULL) {2533 for (psS32 i = 0 ; i < mask->n ; i++) {2534 psTrace("psLib.math", 6, "mask[%d] is %d\n", i, mask->data.PS_TYPE_VECTOR_MASK_DATA[i]);2535 }2536 }2537 }2538 2539 if (!psVectorFitPolynomial4D (poly, mask, maskValue, f, fErr, x, y, z, t)) {2540 psError(PS_ERR_UNKNOWN, false, "Could not fit a polynomial to the data. Returning NULL.\n");2541 psFree(resid);2542 return false;2543 }2544 2545 psVector *fit = psPolynomial4DEvalVector (poly, x, y, z, t);2546 if (fit == NULL) {2547 psError(PS_ERR_UNKNOWN, false, "Could not call psPolynomial4DEvalVector(). Returning NULL.\n");2548 psFree(resid);2549 return false;2550 }2551 for (psS32 i = 0 ; i < f->n ; i++) {2552 if (f->type.type == PS_TYPE_F64) {2553 resid->data.F64[i] = f->data.F64[i] - fit->data.F64[i];2554 } else {2555 resid->data.F64[i] = ((psF64) f->data.F32[i]) - fit->data.F64[i];2556 }2557 }2558 2559 if (psTraceGetLevel("psLib.math") >= 6) {2560 if (mask != NULL) {2561 for (psS32 i = 0 ; i < mask->n ; i++) {2562 if (!((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue))) {2563 psTrace("psLib.math", 6, "(f, fit)[%d] is (%f, %f). resid is (%f)\n",2564 i, f->data.F32[i], fit->data.F32[i], resid->data.F64[i]);2565 }2566 }2567 }2568 }2569 2570 if (!psVectorStats(stats, resid, NULL, mask, maskValue)) {2571 psError(PS_ERR_UNKNOWN, false, "Could not compute statistics on the resid vector. Returning NULL.\n");2572 psFree(resid);2573 psFree(fit);2574 return false;2575 }2576 2577 double meanValue = psStatsGetValue (stats, meanOption);2578 double stdevValue = psStatsGetValue (stats, stdevOption);2579 2580 psTrace("psLib.math", 5, "Mean is %f\n", meanValue);2581 psTrace("psLib.math", 5, "Stdev is %f\n", stdevValue);2582 psF32 minClipValue = -minClipSigma*stdevValue;2583 psF32 maxClipValue = +maxClipSigma*stdevValue;2584 2585 // set mask if pts are not valid2586 // we are masking out any point which is out of range2587 // recovery is not allowed with this scheme2588 for (psS32 i = 0; i < resid->n; i++) {2589 if ((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) {2590 continue;2591 }2592 2593 if ((resid->data.F64[i] - meanValue > maxClipValue) || (resid->data.F64[i] - meanValue < minClipValue)) {2594 if (f->type.type == PS_TYPE_F64) {2595 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n",2596 i, fit->data.F64[i], i, resid->data.F64[i]);2597 } else {2598 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n",2599 i, fit->data.F32[i], i, resid->data.F64[i]);2600 }2601 2602 if (mask != NULL) {2603 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= 0x01;2604 }2605 continue;2606 }2607 Nkeep++;2608 }2609 psTrace("psLib.math", 6, "keeping %d of %ld pts for fit\n", Nkeep, x->n);2610 stats->clippedNvalues = Nkeep;2611 psFree (fit);2612 }2613 // Free local temporary variables2614 psFree (resid);2615 2616 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__);2617 return true;2618 } -
branches/eam_branches/ipp-20230313/psLib/src/math/psMinimizePolyFit.h
r42492 r42506 144 144 ); 145 145 146 bool psVectorIRLSFitPolynomial2D( 147 psPolynomial2D *poly, 148 psStats *stats, 149 const psVector *mask, 150 psVectorMaskType maskValue, 151 const psVector *f, 152 const psVector *fErr, 153 const psVector *x, 154 const psVector *y 155 ); 156 157 bool psVectorIRLSFitPolynomial3D( 158 psPolynomial3D *poly, 159 psStats *stats, 160 const psVector *mask, 161 psVectorMaskType maskValue, 162 const psVector *f, 163 const psVector *fErr, 164 const psVector *x, 165 const psVector *y, 166 const psVector *z 167 ); 168 169 bool psVectorIRLSFitPolynomial4D( 170 psPolynomial4D *poly, 171 psStats *stats, 172 const psVector *mask, 173 psVectorMaskType maskValue, 174 const psVector *f, 175 const psVector *fErr, 176 const psVector *x, 177 const psVector *y, 178 const psVector *z, 179 const psVector *t 180 ); 181 146 182 /// @} 147 183 #endif // #ifndef PS_MINIMIZE_POLYFIT_H -
branches/eam_branches/ipp-20230313/psLib/src/math/psPolynomial.c
r42492 r42506 944 944 bool match = true; 945 945 match &= (poly->type == type); 946 match &= (poly->nX == type);946 match &= (poly->nX == nX); 947 947 948 948 if (!match) { 949 psFree (poly->coeff); 950 psFree (poly->coeffErr); 951 psFree (poly->coeffMask); 949 polynomial1DFree (poly); // frees the coeffs 952 950 953 951 poly->type = type; 954 poly->nX = nX;952 poly->nX = nX; 955 953 956 954 poly->coeff = psAlloc((1 + nX) * sizeof(psF64)); … … 976 974 bool match = true; 977 975 match &= (poly->type == type); 978 match &= (poly->nX == type);979 match &= (poly->nY == type);976 match &= (poly->nX == nX); 977 match &= (poly->nY == nY); 980 978 981 979 if (!match) { 982 for (int i = 0; i < poly->nX + 1; i++) { 983 psFree (poly->coeff[i]); 984 psFree (poly->coeffErr[i]); 985 psFree (poly->coeffMask[i]); 986 } 987 psFree (poly->coeff); 988 psFree (poly->coeffErr); 989 psFree (poly->coeffMask); 980 polynomial2DFree (poly); // frees the coeffs 990 981 991 982 poly->type = type; 992 poly->nX = nX;993 poly->nY = nY;983 poly->nX = nX; 984 poly->nY = nY; 994 985 995 986 poly->coeff = psAlloc((1 + nX) * sizeof(psF64 *)); … … 1012 1003 } 1013 1004 1014 // XXX 3D, 4D versions 1005 bool psPolynomial3DRecycle(psPolynomial3D *poly, 1006 psPolynomialType type, 1007 unsigned int nX, 1008 unsigned int nY, 1009 unsigned int nZ) 1010 { 1011 PS_ASSERT_INT_NONNEGATIVE(nX, NULL); 1012 PS_ASSERT_INT_NONNEGATIVE(nY, NULL); 1013 PS_ASSERT_INT_NONNEGATIVE(nZ, NULL); 1014 1015 bool match = true; 1016 match &= (poly->type == type); 1017 match &= (poly->nX == nX); 1018 match &= (poly->nY == nY); 1019 match &= (poly->nZ == nZ); 1020 1021 if (!match) { 1022 polynomial3DFree (poly); // frees the coeffs 1023 1024 poly->type = type; 1025 poly->nX = nX; 1026 poly->nY = nY; 1027 poly->nZ = nZ; 1028 1029 poly->coeff = psAlloc((nX + 1) * sizeof(psF64 **)); 1030 poly->coeffErr = psAlloc((nX + 1) * sizeof(psF64 **)); 1031 poly->coeffMask = (psMaskType ***)psAlloc((nX + 1) * sizeof(psMaskType **)); 1032 for (int ix = 0; ix < (1 + nX); ix++) { 1033 poly->coeff[ix] = psAlloc((nY + 1) * sizeof(psF64 *)); 1034 poly->coeffErr[ix] = psAlloc((nY + 1) * sizeof(psF64 *)); 1035 poly->coeffMask[ix] = (psMaskType **)psAlloc((nY + 1) * sizeof(psMaskType *)); 1036 for (int iy = 0; iy < (nY + 1); iy++) { 1037 poly->coeff[ix][iy] = psAlloc((nZ + 1) * sizeof(psF64)); 1038 poly->coeffErr[ix][iy] = psAlloc((nZ + 1) * sizeof(psF64)); 1039 poly->coeffMask[ix][iy] = (psMaskType *)psAlloc((nZ + 1) * sizeof(psMaskType)); 1040 } 1041 } 1042 } 1043 for (int ix = 0; ix < (1 + nX); ix++) { 1044 for (int iy = 0; iy < (1 + nY); iy++) { 1045 for (int iz = 0; iz < (1 + nZ); iz++) { 1046 poly->coeff[ix][iy][iz] = 0.0; 1047 poly->coeffErr[ix][iy][iz] = 0.0; 1048 poly->coeffMask[ix][iy][iz] = PS_POLY_MASK_NONE; 1049 } 1050 } 1051 } 1052 return(true); 1053 } 1054 1055 bool psPolynomial4DRecycle(psPolynomial4D *poly, 1056 psPolynomialType type, 1057 unsigned int nX, 1058 unsigned int nY, 1059 unsigned int nZ, 1060 unsigned int nT) 1061 { 1062 PS_ASSERT_INT_NONNEGATIVE(nX, NULL); 1063 PS_ASSERT_INT_NONNEGATIVE(nY, NULL); 1064 PS_ASSERT_INT_NONNEGATIVE(nZ, NULL); 1065 PS_ASSERT_INT_NONNEGATIVE(nT, NULL); 1066 1067 bool match = true; 1068 match &= (poly->type == type); 1069 match &= (poly->nX == nX); 1070 match &= (poly->nY == nY); 1071 match &= (poly->nZ == nZ); 1072 match &= (poly->nT == nT); 1073 1074 if (!match) { 1075 polynomial4DFree (poly); // frees the coeffs 1076 1077 poly->type = type; 1078 poly->nX = nX; 1079 poly->nY = nY; 1080 poly->nZ = nZ; 1081 poly->nT = nT; 1082 1083 poly->coeff = psAlloc((nX + 1) * sizeof(psF64 ***)); 1084 poly->coeffErr = psAlloc((nX + 1) * sizeof(psF64 ***)); 1085 poly->coeffMask = (psMaskType ****)psAlloc((nX + 1) * sizeof(psMaskType ***)); 1086 for (int ix = 0; ix < (nX + 1); ix++) { 1087 poly->coeff[ix] = psAlloc((nY + 1) * sizeof(psF64 **)); 1088 poly->coeffErr[ix] = psAlloc((nY + 1) * sizeof(psF64 **)); 1089 poly->coeffMask[ix] = (psMaskType ***)psAlloc((nY + 1) * sizeof(psMaskType **)); 1090 for (int iy = 0; iy < (nY + 1); iy++) { 1091 poly->coeff[ix][iy] = psAlloc((nZ + 1) * sizeof(psF64 *)); 1092 poly->coeffErr[ix][iy] = psAlloc((nZ + 1) * sizeof(psF64 *)); 1093 poly->coeffMask[ix][iy] = (psMaskType **)psAlloc((nZ + 1) * sizeof(psMaskType *)); 1094 for (int iz = 0; iz < (nZ + 1); iz++) { 1095 poly->coeff[ix][iy][iz] = psAlloc((nT + 1) * sizeof(psF64)); 1096 poly->coeffErr[ix][iy][iz] = psAlloc((nT + 1) * sizeof(psF64)); 1097 poly->coeffMask[ix][iy][iz] = (psMaskType *)psAlloc((nT + 1) * sizeof(psMaskType)); 1098 } 1099 } 1100 } 1101 } 1102 for (int ix = 0; ix < (1 + nX); ix++) { 1103 for (int iy = 0; iy < (1 + nY); iy++) { 1104 for (int iz = 0; iz < (1 + nZ); iz++) { 1105 for (int it = 0; it < (1 + nT); it++) { 1106 poly->coeff[ix][iy][iz][it] = 0.0; 1107 poly->coeffErr[ix][iy][iz][it] = 0.0; 1108 poly->coeffMask[ix][iy][iz][it] = PS_POLY_MASK_NONE; 1109 } 1110 } 1111 } 1112 } 1113 return(true); 1114 } 1115 1116 // ######## Copy polynomials ######## 1015 1117 psPolynomial1D *psPolynomial1DCopy(psPolynomial1D *out, 1016 psPolynomial1D *poly)1118 psPolynomial1D *poly) 1017 1119 { 1018 1120 if (out == NULL) { 1019 out = psPolynomial1DAlloc (poly->type, poly->nX);1121 out = psPolynomial1DAlloc (poly->type, poly->nX); 1020 1122 } else { 1021 psPolynomial1DRecycle (out, poly->type, poly->nX);1123 psPolynomial1DRecycle (out, poly->type, poly->nX); 1022 1124 } 1023 1125 … … 1030 1132 } 1031 1133 psPolynomial2D *psPolynomial2DCopy(psPolynomial2D *out, 1032 psPolynomial2D *poly)1134 psPolynomial2D *poly) 1033 1135 { 1034 1136 if (out == NULL) { 1035 out = psPolynomial2DAlloc (poly->type, poly->nX, poly->nY);1137 out = psPolynomial2DAlloc (poly->type, poly->nX, poly->nY); 1036 1138 } else { 1037 psPolynomial2DRecycle (out, poly->type, poly->nX, poly->nY);1139 psPolynomial2DRecycle (out, poly->type, poly->nX, poly->nY); 1038 1140 } 1039 1141 1040 1142 for (int i = 0; i < (1 + poly->nX); i++) { 1041 for (int j = 0; j < (1 + poly->nY); j++) { 1042 out->coeff[i][j] = poly->coeff[i][j]; 1043 out->coeffErr[i][j] = poly->coeffErr[i][j]; 1044 out->coeffMask[i][j] = poly->coeffMask[i][j]; 1045 } 1143 for (int j = 0; j < (1 + poly->nY); j++) { 1144 out->coeff[i][j] = poly->coeff[i][j]; 1145 out->coeffErr[i][j] = poly->coeffErr[i][j]; 1146 out->coeffMask[i][j] = poly->coeffMask[i][j]; 1147 } 1148 } 1149 return(out); 1150 } 1151 psPolynomial3D *psPolynomial3DCopy(psPolynomial3D *out, 1152 psPolynomial3D *poly) 1153 { 1154 if (out == NULL) { 1155 out = psPolynomial3DAlloc (poly->type, poly->nX, poly->nY, poly->nZ); 1156 } else { 1157 psPolynomial3DRecycle (out, poly->type, poly->nX, poly->nY, poly->nZ); 1158 } 1159 1160 for (int ix = 0; ix < (1 + poly->nX); ix++) { 1161 for (int iy = 0; iy < (1 + poly->nY); iy++) { 1162 for (int iz = 0; iz < (1 + poly->nZ); iz++) { 1163 out->coeff[ix][iy][iz] = poly->coeff[ix][iy][iz]; 1164 out->coeffErr[ix][iy][iz] = poly->coeffErr[ix][iy][iz]; 1165 out->coeffMask[ix][iy][iz] = poly->coeffMask[ix][iy][iz]; 1166 } 1167 } 1168 } 1169 return(out); 1170 } 1171 psPolynomial4D *psPolynomial4DCopy(psPolynomial4D *out, 1172 psPolynomial4D *poly) 1173 { 1174 if (out == NULL) { 1175 out = psPolynomial4DAlloc (poly->type, poly->nX, poly->nY, poly->nZ, poly->nT); 1176 } else { 1177 psPolynomial4DRecycle (out, poly->type, poly->nX, poly->nY, poly->nZ, poly->nT); 1178 } 1179 1180 for (int ix = 0; ix < (1 + poly->nX); ix++) { 1181 for (int iy = 0; iy < (1 + poly->nY); iy++) { 1182 for (int iz = 0; iz < (1 + poly->nZ); iz++) { 1183 for (int it = 0; it < (1 + poly->nT); it++) { 1184 out->coeff[ix][iy][iz][it] = poly->coeff[ix][iy][iz][it]; 1185 out->coeffErr[ix][iy][iz][it] = poly->coeffErr[ix][iy][iz][it]; 1186 out->coeffMask[ix][iy][iz][it] = poly->coeffMask[ix][iy][iz][it]; 1187 } 1188 } 1189 } 1046 1190 } 1047 1191 return(out); … … 1080 1224 1081 1225 switch (x->type.type) { 1082 case PS_TYPE_F64:1226 case PS_TYPE_F64: 1083 1227 tmp = psVectorAlloc(x->n, PS_TYPE_F64); 1084 1228 for (unsigned int i=0;i<x->n;i++) { … … 1086 1230 } 1087 1231 break; 1088 case PS_TYPE_F32:1232 case PS_TYPE_F32: 1089 1233 tmp = psVectorAlloc(x->n, PS_TYPE_F32); 1090 1234 for (unsigned int i=0;i<x->n;i++) { … … 1092 1236 } 1093 1237 break; 1094 default:1238 default: 1095 1239 psError(PS_ERR_UNKNOWN, false, "invalid input data type.\n"); 1096 1240 return (NULL); -
branches/eam_branches/ipp-20230313/psLib/src/math/psPolynomial.h
r42492 r42506 164 164 psPolynomialType type, 165 165 unsigned int nX); 166 167 166 bool psPolynomial2DRecycle(psPolynomial2D *poly, 168 167 psPolynomialType type, 169 168 unsigned int nX, 170 169 unsigned int nY); 170 bool psPolynomial3DRecycle(psPolynomial3D *poly, 171 psPolynomialType type, 172 unsigned int nX, 173 unsigned int nY, 174 unsigned int nZ); 175 bool psPolynomial4DRecycle(psPolynomial4D *poly, 176 psPolynomialType type, 177 unsigned int nX, 178 unsigned int nY, 179 unsigned int nZ, 180 unsigned int nT); 171 181 172 182 psPolynomial1D *psPolynomial1DCopy(psPolynomial1D *out, 173 183 psPolynomial1D *poly); 174 175 184 psPolynomial2D *psPolynomial2DCopy(psPolynomial2D *out, 176 185 psPolynomial2D *poly); 186 psPolynomial3D *psPolynomial3DCopy(psPolynomial3D *out, 187 psPolynomial3D *poly); 188 psPolynomial4D *psPolynomial4DCopy(psPolynomial4D *out, 189 psPolynomial4D *poly); 177 190 178 191 /** Evaluates a 1-D polynomial at specific coordinates. -
branches/eam_branches/ipp-20230313/psLib/test/math
- Property svn:ignore
-
old new 56 56 tap_psMinimizeLMM_Alt 57 57 tap_psMinimizeLMM_Trail 58 tap_psPolyFit_IRLS 58 tap_psPolyFit_IRLS_1D 59 tap_psPolyFit_IRLS_2D 59 60 tap_psPolynomialMD_sampleDark 60 61 test-suite.log
-
- Property svn:ignore
Note:
See TracChangeset
for help on using the changeset viewer.
