Changeset 42319
- Timestamp:
- Jan 23, 2023, 7:10:15 AM (3 years ago)
- Location:
- branches/eam_branches/psLib.20230123
- Files:
-
- 3 edited
-
src/math/psSpline.c (modified) (9 diffs)
-
src/math/psSpline.h (modified) (4 diffs)
-
test/math/tap_psSpline1D.c (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/psLib.20230123/src/math/psSpline.c
r23486 r42319 1 1 /** @file psSpline.c 2 * 3 * @brief Contains basic spline allocation, deallocation, fitting, 4 * and evaluation routines. 5 * 6 * This file contains the routines that allocate, free, and evaluate splines. 7 * 8 * @version $Revision: 1.158 $ $Name: not supported by cvs2svn $ 9 * @date $Date: 2007-03-14 02:36:28 $ 10 * 11 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 2 re-written by EAM 2023.01.23 12 3 */ 13 4 … … 16 7 #endif 17 8 18 /*****************************************************************************/19 /* INCLUDE FILES */20 /*****************************************************************************/21 9 #include <stdio.h> 22 10 #include <stdbool.h> … … 36 24 #include "psMathUtils.h" 37 25 38 /*****************************************************************************/ 39 /* DEFINE STATEMENTS */ 40 /*****************************************************************************/ 41 42 /*****************************************************************************/ 43 /* TYPE DEFINITIONS */ 44 /*****************************************************************************/ 45 46 /*****************************************************************************/ 47 /* GLOBAL VARIABLES */ 48 /*****************************************************************************/ 49 50 /*****************************************************************************/ 51 /* FILE STATIC VARIABLES */ 52 /*****************************************************************************/ 53 54 /*****************************************************************************/ 55 /* FUNCTION IMPLEMENTATION - LOCAL */ 56 /*****************************************************************************/ 57 58 static void spline1DFree(psSpline1D *tmpSpline) 59 { 60 if (tmpSpline == NULL) { 61 return; 62 } 26 static void psSpline1DFree(psSpline1D *tmpSpline) 27 { 28 if (tmpSpline == NULL) return; 63 29 64 30 if (tmpSpline->spline != NULL) { … … 78 44 } 79 45 80 81 static void PS_POLY1D_PRINT(82 psPolynomial1D *poly)83 {84 printf("-------------- PS_POLY1D_PRINT() --------------\n");85 printf("poly->nX is %d\n", poly->nX);86 for (psS32 i = 0 ; i < (1 + poly->nX) ; i++) {87 printf("poly->coeff[%d] is %f\n", i, poly->coeff[i]);88 }89 }90 91 46 static void PS_PRINT_SPLINE2(psSpline1D *mySpline) 92 47 { … … 94 49 printf("mySpline->n is %d\n", mySpline->n); 95 50 for (psS32 i = 0 ; i < mySpline->n ; i++) { 96 PS_POLY1D_PRINT(mySpline->spline[i]); 97 } 98 PS_VECTOR_PRINT_F32(mySpline->knots); 51 // print the knots 52 } 99 53 } 100 54 101 55 /***************************************************************************** 102 CalculateSecondDerivs(): Given a set of x/y vectors corresponding to a 103 tabulated function at n points, this routine calculates the second 104 derivatives of the interpolating cubic splines at those n points. 105 106 The first and second derivatives at the endpoints were previously undefined in 107 the SDR. From bugzilla #???, they are required to be 0.0, implementing natural 108 splines. 109 110 Endpoints are defined by 111 PS_LEFT_SPLINE_DERIV 112 PS_RIGHT_SPLINE_DERIV 113 114 This routine assumes that vectors x and y are of the appropriate types/sizes 115 (F32). 116 117 XXX: use recycled vectors for internal data. 118 XXX: do an F64 version? 56 CalculateSecondDerivs(): Given a set of x,y vectors corresponding to the spline knots, this 57 routine calculates the second derivatives of the interpolating cubic splines at those n points. 58 59 The boundary conditions may be: 60 * first derivative specified OR 61 * second derivatives = 0 62 63 One or the other condition may be true for each of the upper and lower bounds 64 65 NOTE: vectors must be F32 66 119 67 *****************************************************************************/ 120 #define PS_LEFT_SPLINE_DERIV 0.0 121 #define PS_RIGHT_SPLINE_DERIV 0.0 68 122 69 static psF32 *calculateSecondDerivs( 123 const psVector* x, ///< Ordinates 124 const psVector* y) ///< Coordinates 70 const psVector* x, ///< Ordinates 71 const psVector* y, ///< Coordinates 72 psF32 dyLower; // if not NAN, lower-bound 1st derivative is defined 73 psF32 dyUpper; // if not NAN, lower-bound 1st derivative is defined 74 ) 125 75 { 126 76 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__); … … 190 140 191 141 /***************************************************************************** 192 ps VectorFitSpline1D(): given a set of x/y vectors, this routine generates the142 psSpline1DFitVector(): given a set of x/y vectors, this routine generates the 193 143 linear or cublic splines which satisfy those data points. 194 144 … … 209 159 XXX: What types must be supported? 210 160 *****************************************************************************/ 211 psSpline1D *ps VectorFitSpline1D(161 psSpline1D *psSpline1DFitVector( 212 162 const psVector* x, ///< Ordinates. 213 163 const psVector* y) ///< Coordinates. … … 361 311 psF64? 362 312 *****************************************************************************/ 363 float psSpline1DEval (364 const psSpline1D *spline,313 float psSpline1DEval_Old( 314 const psSpline1D_Old *spline, 365 315 float x) 366 316 { … … 397 347 } 398 348 349 // XXX EAM : changing implementation to use yKnot, d2yKnot instead of polynomials 350 float psSpline1DEval_New( 351 const psSpline1D *spline, 352 float x) 353 { 354 psTrace("psLib.math", 3, "---- %s() begin ----\n", __func__); 355 PS_ASSERT_PTR_NON_NULL(spline, NAN); 356 PS_ASSERT_INT_NONNEGATIVE(spline->n, NAN); 357 PS_ASSERT_VECTOR_TYPE(spline->knots, PS_TYPE_F32, NAN); 358 359 psS32 n = spline->n; 360 if ((x < spline->knots->data.F32[0]) || (x > spline->knots->data.F32[spline->knots->n-1])) { 361 // If x is outside the range of spline->knots, generate a warning 362 // message, then return the left, or right, endpoint. 363 psLogMsg(__func__, PS_LOG_WARN, 364 "psSpline1DEval(): x ordinate (%f) is outside the spline range (%f - %f) (%d).", 365 x, spline->knots->data.F32[0], spline->knots->data.F32[n-1], n); 366 367 psS32 binNum = (x < spline->knots->data.F32[0]) ? 0 : n-1; 368 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__); 369 return(psPolynomial1DEval(spline->spline[binNum], x)); 370 } 371 372 psScalar tmpScalar; 373 tmpScalar.type.type = PS_TYPE_F32; 374 tmpScalar.data.F32 = x; 375 psVectorBinaryDisectResult result; 376 psS32 binNum = psVectorBinaryDisect(&result, spline->knots, &tmpScalar); 377 if (result != PS_BINARY_DISECT_PASS) { 378 psError(PS_ERR_UNKNOWN, false, "Could not perform bin dissection on spline->knots.\n"); 379 return(NAN); 380 } 381 382 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__); 383 return(psPolynomial1DEval(spline->spline[binNum], x)); 384 } 385 399 386 400 387 /***************************************************************************** -
branches/eam_branches/psLib.20230123/src/math/psSpline.h
r23486 r42319 5 5 * and evaluate splines. 6 6 * 7 * @author GLG, MHPCC 7 * @author GLG (MHPCC) 8 * reworked by EAM (IfA) 8 9 * 9 10 * @version $Revision: 1.62 $ $Name: not supported by cvs2svn $ … … 27 28 #include "psPolynomial.h" 28 29 29 #define PS_LEFT_SPLINE_DERIV 0.0 30 #define PS_RIGHT_SPLINE_DERIV 0.0 31 32 /** One-Dimensional Spline */ 30 /** One-Dimensional Spline 31 This structure represents a 1D cubic spline. Note the option for 32 equally-spaced knots allows a quick selection of the correct spline 33 segment. The values (xMin, xMax, xDel) are stored for ease of access. 34 */ 33 35 typedef struct 34 36 { 35 37 unsigned int n; ///< The number of spline pieces 36 psPolynomial1D **spline; ///< An array of n pointers to the spline polynomials 37 psVector *knots; ///< The boundaries between each spline piece. Size is n+1. 38 psF32 *p_psDeriv2; ///< For cubic splines, the second derivative at each domain point. Size is n+1. 38 psF32 *xKnots; ///< x-coordinate of the knots (n+1) 39 psF32 *yKnots; ///< y-coordinate of the knots (n+1) 40 psF32 *d2yKnots; ///< 2nd derivative of y at the knots (n+1) 41 bool equalSpacing; // if knots are equally spaced, the seqment choice can be optimized 42 psF32 xMin; // for equally-spaced knots, the value at the lower bound (xKnots[0]) 43 psF32 xMax; // for equally-spaced knots, the value at the upper bound (xKnots[n]) 44 psF32 xDel; // for equally-spaced knots, the spacing (xKnots[n] - xKnots[0])/n 39 45 } 40 46 psSpline1D; 41 47 42 /** Allocates a psSpline1D structure 43 * 44 * Allocator for psSpline1D. 48 /** Allocator for psSpline1D. 45 49 * 46 50 * @return psSpline1D* new 1-D spline struct … … 53 57 */ 54 58 float psSpline1DEval( 55 const psSpline1D *spline, ///< Coefficients for spline polynomials59 const psSpline1D *spline, ///< spline pointer 56 60 float x ///< location at which to evaluate 57 61 ); … … 71 75 * generates the linear splines which satisfy those data points. 72 76 * 77 * XXX EAM: add option to generate / select a subset of knots from the data 78 * 73 79 * @return psSpline1D*: the calculated one-dimensional splines 74 80 */ 75 psSpline1D *ps VectorFitSpline1D(81 psSpline1D *psSpline1DFitVector( 76 82 const psVector* x, ///< Ordinates (or NULL to just use the indices) 77 83 const psVector* y ///< Coordinates -
branches/eam_branches/psLib.20230123/test/math/tap_psSpline1D.c
r13124 r42319 1 /* @file t st_psImageManip.c2 * 3 * @brief This file will containtests for all of the public psLib functions1 /* @file tap_psImageManip.c 2 * 3 * @brief This file contains tests for all of the public psLib functions 4 4 * that implement 1-D spline functionality: 5 5 * psSpline1DAlloc() 6 6 * psSpline1DEval() 7 7 * psSpline1DEvalVector() 8 * ps VectorFitSpline1D()8 * psSpline1DFitVector() 9 9 * 10 10 * This file is composed of the tests formerly in tst_psFunc02.c, … … 35 35 psF32 expect) 36 36 { 37 // NOTE: this returns NAN if 'expect' == 0.0 38 // NOTE 2: this is not testing a percent, but fractional error 37 39 if ((fabs(actual - expect) / fabs(expect)) > ERROR_TOLERANCE_PERCENT) { 38 40 return(true); … … 83 85 typedef psF64 (*mappingFuncF64)(psF64 x); 84 86 87 /* EAM 2023.01.22 : these tests are not well considered. They generate a set of N+1 points 88 to use as knots at integer values from 0 to N, then evaluate the spline half-way between 89 the knots. the function above is a cubic, so a cubic spline should fit it perfectly, which 90 is fine. Perhaps this test suite should use a pre-defined collection of data points? 91 */ 92 85 93 bool genericF32Test(psS32 NumSplines, mappingFuncF32 func, bool xNull) 86 94 { 87 // We test the ps VectorFitSpline1D, psSpline1DEval() functions. F32 version.95 // We test the psSpline1DFitVector, psSpline1DEval() functions. F32 version. 88 96 bool testStatus = true; 89 97 { 98 // Generate the vector data 90 99 psMemId id = psMemGetId(); 91 100 psVector *xF32 = psVectorAlloc(NumSplines+1, PS_TYPE_F32); … … 98 107 psSpline1D *tmpSpline = NULL; 99 108 if (!xNull) { 100 tmpSpline = ps VectorFitSpline1D(xF32, yF32);109 tmpSpline = psSpline1DFitVector(xF32, yF32); 101 110 } else { 102 tmpSpline = psVectorFitSpline1D(NULL, yF32); 103 } 111 tmpSpline = psSpline1DFitVector(NULL, yF32); 112 } 113 104 114 if(tmpSpline == NULL) { 105 diag("ps VectorFitSpline1D() returned NULL");115 diag("psSpline1DFitVector() returned NULL"); 106 116 testStatus = false; 107 117 } else { 108 118 if (tmpSpline->n != NumSplines) { 109 diag("ps VectorFitSpline1D() did not properly set the psSpline1D->n member");119 diag("psSpline1DFitVector() did not properly set the psSpline1D->n member"); 110 120 testStatus = false; 111 121 } 112 122 if(tmpSpline->spline == NULL) { 113 diag("ps VectorFitSpline1D() returned a NULL psSpline1D->spline member.");123 diag("psSpline1DFitVector() returned a NULL psSpline1D->spline member."); 114 124 testStatus = false; 115 125 } 116 126 for (psS32 i = 0 ; i < NumSplines ; i++) { 117 127 if (tmpSpline->spline[i] == NULL) { 118 diag("ps VectorFitSpline1D() returned a NULL psSpline1D->spline[%d] member.", i);128 diag("psSpline1DFitVector() returned a NULL psSpline1D->spline[%d] member.", i); 119 129 testStatus = false; 120 130 } 121 131 } 122 132 if (tmpSpline->knots == NULL) { 123 diag("ps VectorFitSpline1D() returned a NULL psSpline1D->knots member");133 diag("psSpline1DFitVector() returned a NULL psSpline1D->knots member"); 124 134 testStatus = false; 125 135 } 126 136 if (tmpSpline->p_psDeriv2 == NULL) { 127 diag("ps VectorFitSpline1D()returned a NULL psSpline1D->p_psDeriv2 member");137 diag("psSpline1DFitVector()returned a NULL psSpline1D->p_psDeriv2 member"); 128 138 testStatus = false; 129 139 } … … 136 146 testStatus = false; 137 147 diag("TEST ERROR: f(%f) is %f, should be %f", x, y, myFunc00(x)); 148 // XXX EAM : the truth value above should be 'func' not myFunc00 138 149 } 139 150 } … … 150 161 diag("TEST ERROR: f(%f) is %f, should be %f", xF32->data.F32[i], 151 162 yF32Test->data.F32[i], myFunc00(xF32->data.F32[i])); 163 // XXX EAM : the truth value above should be 'func' not myFunc00 152 164 } 153 165 } … … 171 183 bool genericF64Test(psS32 NumSplines, mappingFuncF64 func, bool xNull) 172 184 { 173 // We test the ps VectorFitSpline1D, psSpline1DEval() functions. F64 version.185 // We test the psSpline1DFitVector, psSpline1DEval() functions. F64 version. 174 186 bool testStatus = true; 175 187 { … … 184 196 psSpline1D *tmpSpline = NULL; 185 197 if (!xNull) { 186 tmpSpline = ps VectorFitSpline1D(xF64, yF64);198 tmpSpline = psSpline1DFitVector(xF64, yF64); 187 199 } else { 188 tmpSpline = ps VectorFitSpline1D(NULL, yF64);200 tmpSpline = psSpline1DFitVector(NULL, yF64); 189 201 } 190 202 if(tmpSpline == NULL) { 191 diag("ps VectorFitSpline1D() returned NULL");203 diag("psSpline1DFitVector() returned NULL"); 192 204 testStatus = false; 193 205 } else { 194 206 if (tmpSpline->n != NumSplines) { 195 diag("ps VectorFitSpline1D() did not properly set the psSpline1D->n member");207 diag("psSpline1DFitVector() did not properly set the psSpline1D->n member"); 196 208 testStatus = false; 197 209 } 198 210 if(tmpSpline->spline == NULL) { 199 diag("ps VectorFitSpline1D() returned a NULL psSpline1D->spline member.");211 diag("psSpline1DFitVector() returned a NULL psSpline1D->spline member."); 200 212 testStatus = false; 201 213 } 202 214 for (psS32 i = 0 ; i < NumSplines ; i++) { 203 215 if (tmpSpline->spline[i] == NULL) { 204 diag("ps VectorFitSpline1D() returned a NULL psSpline1D->spline[%d] member.", i);216 diag("psSpline1DFitVector() returned a NULL psSpline1D->spline[%d] member.", i); 205 217 testStatus = false; 206 218 } 207 219 } 208 220 if (tmpSpline->knots == NULL) { 209 diag("ps VectorFitSpline1D() returned a NULL psSpline1D->knots member");221 diag("psSpline1DFitVector() returned a NULL psSpline1D->knots member"); 210 222 testStatus = false; 211 223 } 212 224 if (tmpSpline->p_psDeriv2 == NULL) { 213 diag("ps VectorFitSpline1D()returned a NULL psSpline1D->p_psDeriv2 member");225 diag("psSpline1DFitVector()returned a NULL psSpline1D->p_psDeriv2 member"); 214 226 testStatus = false; 215 227 } … … 274 286 } 275 287 276 // psSplineEvalTest_sub(): Call ps VectorFitSpline1Dwith NULL arguments.277 { 278 psMemId id = psMemGetId(); 279 psSpline1D *tmpSpline = ps VectorFitSpline1D(NULL, NULL);280 ok(tmpSpline == NULL, "ps VectorFitSpline1D() returns NULL with NULL arguments");288 // psSplineEvalTest_sub(): Call psSpline1DFitVector with NULL arguments. 289 { 290 psMemId id = psMemGetId(); 291 psSpline1D *tmpSpline = psSpline1DFitVector(NULL, NULL); 292 ok(tmpSpline == NULL, "psSpline1DFitVector() returns NULL with NULL arguments"); 281 293 ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks"); 282 294 } … … 287 299 psMemId id = psMemGetId(); 288 300 float y = psSpline1DEval(NULL, 0.0); 289 ok(isnan(y), "psSpline1DEval() returned NAN wi llNULL input spline");301 ok(isnan(y), "psSpline1DEval() returned NAN with NULL input spline"); 290 302 ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks"); 291 303 } … … 297 309 psVector *x = psVectorAlloc(10, PS_TYPE_F32); 298 310 psVector *y = psSpline1DEvalVector(NULL, x); 299 ok(y == NULL, "psSpline1DEvalVector() returned N AN willNULL input spline");311 ok(y == NULL, "psSpline1DEvalVector() returned NULL with NULL input spline"); 300 312 psFree(x); 301 313 psFree(y); … … 316 328 ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks"); 317 329 } 318 319 330 320 331 ok(genericF32Test(1, myFunc00, false), "Generic, simple mapping, F32 test. 1 spline");
Note:
See TracChangeset
for help on using the changeset viewer.
