|
7 | 7 | using VectorN1 = cip::VectorN<double, 1>; |
8 | 8 | using VectorN2 = cip::VectorN<double, 2>; |
9 | 9 | using VectorN3 = cip::VectorN<double, 3>; |
| 10 | +using VectorN4 = cip::VectorN<double, 4>; |
10 | 11 | using Span = std::span<const double>; |
11 | 12 | using Pr = std::pair<size_t, size_t>; |
12 | 13 |
|
@@ -197,3 +198,164 @@ TEST(TestInterp3D, test_linear_interp_3d) { |
197 | 198 | ASSERT_TRUE(cip::Interp3DAssertions<cip::LinearInterp3D<double>>(x, y, z, f, x_fine, y_fine, z_fine, f_fine)); |
198 | 199 |
|
199 | 200 | } |
| 201 | + |
| 202 | +/** |
| 203 | + * Test for 4D linear interpolation |
| 204 | + * |
| 205 | + * This test demonstrates using the InterpNDAssertions class with N=4 dimensions. |
| 206 | + * We use a simple 4D linear function f(x,y,z,w) = a*x + b*y + c*z + d*w + e |
| 207 | + * to generate the test data, which should be perfectly interpolated by a linear interpolator. |
| 208 | + */ |
| 209 | +TEST(TestInterp4D, test_linear_interp_4d) { |
| 210 | + // Create grid vectors for each dimension |
| 211 | + cip::Vector x = { 0.0, 1.0, 2.0 }; |
| 212 | + cip::Vector y = { 0.0, 1.0, 2.0 }; |
| 213 | + cip::Vector z = { 0.0, 1.0, 2.0 }; |
| 214 | + cip::Vector w = { 0.0, 1.0, 2.0 }; |
| 215 | + |
| 216 | + // Define a linear function coefficients: f(x,y,z,w) = 2*x + 3*y - z + 0.5*w + 1 |
| 217 | + const double a = 2.0; |
| 218 | + const double b = 3.0; |
| 219 | + const double c = -1.0; |
| 220 | + const double d = 0.5; |
| 221 | + const double e = 1.0; |
| 222 | + |
| 223 | + // Create 4D function values array |
| 224 | + cip::Vector4 f; |
| 225 | + f.resize(x.size()); |
| 226 | + for (size_t i = 0; i < x.size(); ++i) { |
| 227 | + f[i].resize(y.size()); |
| 228 | + for (size_t j = 0; j < y.size(); ++j) { |
| 229 | + f[i][j].resize(z.size()); |
| 230 | + for (size_t k = 0; k < z.size(); ++k) { |
| 231 | + f[i][j][k].resize(w.size()); |
| 232 | + for (size_t l = 0; l < w.size(); ++l) { |
| 233 | + // Function: f(x,y,z,w) = 2*x + 3*y - z + 0.5*w + 1 |
| 234 | + f[i][j][k][l] = a*x[i] + b*y[j] + c*z[k] + d*w[l] + e; |
| 235 | + } |
| 236 | + } |
| 237 | + } |
| 238 | + } |
| 239 | + |
| 240 | + // Fine grid for testing interpolation |
| 241 | + cip::Vector x_fine = { 0.0, 0.5, 1.0, 1.5, 2.0 }; |
| 242 | + cip::Vector y_fine = { 0.0, 0.5, 1.0, 1.5, 2.0 }; |
| 243 | + cip::Vector z_fine = { 0.0, 0.5, 1.0, 1.5, 2.0 }; |
| 244 | + cip::Vector w_fine = { 0.0, 0.5, 1.0, 1.5, 2.0 }; |
| 245 | + |
| 246 | + // Expected values at fine grid points |
| 247 | + cip::Vector4 f_fine; |
| 248 | + f_fine.resize(x_fine.size()); |
| 249 | + for (size_t i = 0; i < x_fine.size(); ++i) { |
| 250 | + f_fine[i].resize(y_fine.size()); |
| 251 | + for (size_t j = 0; j < y_fine.size(); ++j) { |
| 252 | + f_fine[i][j].resize(z_fine.size()); |
| 253 | + for (size_t k = 0; k < z_fine.size(); ++k) { |
| 254 | + f_fine[i][j][k].resize(w_fine.size()); |
| 255 | + for (size_t l = 0; l < w_fine.size(); ++l) { |
| 256 | + // Function: f(x,y,z,w) = 2*x + 3*y - z + 0.5*w + 1 |
| 257 | + f_fine[i][j][k][l] = a*x_fine[i] + b*y_fine[j] + c*z_fine[k] + d*w_fine[l] + e; |
| 258 | + } |
| 259 | + } |
| 260 | + } |
| 261 | + } |
| 262 | + |
| 263 | + // Test the 4D interpolation using our InterpNDAssertions class |
| 264 | + ASSERT_TRUE(cip::Interp4DAssertions<cip::LinearInterp4D<double>>( |
| 265 | + x, y, z, w, f, x_fine, y_fine, z_fine, w_fine, f_fine)); |
| 266 | +} |
| 267 | + |
| 268 | +// Direct test using the InterpNDAssertions template with N=4 |
| 269 | +TEST(TestInterp4D, test_direct_nd_assertions) { |
| 270 | + // Create grid vectors for each dimension |
| 271 | + cip::Vector x = { 0.0, 1.0, 2.0 }; |
| 272 | + cip::Vector y = { 0.0, 1.0, 2.0 }; |
| 273 | + cip::Vector z = { 0.0, 1.0, 2.0 }; |
| 274 | + cip::Vector w = { 0.0, 1.0, 2.0 }; |
| 275 | + |
| 276 | + // Create 4D function values array |
| 277 | + // Function is f(x,y,z,w) = x + y + z + w |
| 278 | + cip::Vector4 f; |
| 279 | + f.resize(x.size()); |
| 280 | + for (size_t i = 0; i < x.size(); ++i) { |
| 281 | + f[i].resize(y.size()); |
| 282 | + for (size_t j = 0; j < y.size(); ++j) { |
| 283 | + f[i][j].resize(z.size()); |
| 284 | + for (size_t k = 0; k < z.size(); ++k) { |
| 285 | + f[i][j][k].resize(w.size()); |
| 286 | + for (size_t l = 0; l < w.size(); ++l) { |
| 287 | + // Function: f(x,y,z,w) = x + y + z + w |
| 288 | + f[i][j][k][l] = x[i] + y[j] + z[k] + w[l]; |
| 289 | + } |
| 290 | + } |
| 291 | + } |
| 292 | + } |
| 293 | + |
| 294 | + // Fine grid for testing interpolation |
| 295 | + cip::Vector x_fine = { 0.0, 0.5, 1.0, 1.5, 2.0 }; |
| 296 | + cip::Vector y_fine = { 0.0, 0.5, 1.0, 1.5, 2.0 }; |
| 297 | + cip::Vector z_fine = { 0.0, 0.5, 1.0, 1.5, 2.0 }; |
| 298 | + cip::Vector w_fine = { 0.0, 0.5, 1.0, 1.5, 2.0 }; |
| 299 | + |
| 300 | + // Expected values at fine grid points |
| 301 | + cip::Vector4 f_fine; |
| 302 | + f_fine.resize(x_fine.size()); |
| 303 | + for (size_t i = 0; i < x_fine.size(); ++i) { |
| 304 | + f_fine[i].resize(y_fine.size()); |
| 305 | + for (size_t j = 0; j < y_fine.size(); ++j) { |
| 306 | + f_fine[i][j].resize(z_fine.size()); |
| 307 | + for (size_t k = 0; k < z_fine.size(); ++k) { |
| 308 | + f_fine[i][j][k].resize(w_fine.size()); |
| 309 | + for (size_t l = 0; l < w_fine.size(); ++l) { |
| 310 | + // Function: f(x,y,z,w) = x + y + z + w |
| 311 | + f_fine[i][j][k][l] = x_fine[i] + y_fine[j] + z_fine[k] + w_fine[l]; |
| 312 | + } |
| 313 | + } |
| 314 | + } |
| 315 | + } |
| 316 | + |
| 317 | + // Pack grid vectors and fine grid vectors into arrays |
| 318 | + std::array<cip::Vector, 4> grid_vectors = {x, y, z, w}; |
| 319 | + std::array<cip::Vector, 4> fine_grid_vectors = {x_fine, y_fine, z_fine, w_fine}; |
| 320 | + |
| 321 | + // Test the 4D interpolation directly using the InterpNDAssertions class |
| 322 | + auto result = cip::InterpNDAssertions<cip::LinearInterp4D<double>, 4, cip::Vector4>::test( |
| 323 | + grid_vectors, f, fine_grid_vectors, f_fine); |
| 324 | + ASSERT_TRUE(result); |
| 325 | +} |
| 326 | + |
| 327 | +// Test a non-linear function with 4D interpolation |
| 328 | +TEST(TestInterp4D, test_nonlinear_4d) { |
| 329 | + // Create grid vectors for each dimension |
| 330 | + cip::Vector x = { 0.0, 1.0, 2.0 }; |
| 331 | + cip::Vector y = { 0.0, 1.0, 2.0 }; |
| 332 | + cip::Vector z = { 0.0, 1.0, 2.0 }; |
| 333 | + cip::Vector w = { 0.0, 1.0, 2.0 }; |
| 334 | + |
| 335 | + // Create 4D function values array for a quadratic function |
| 336 | + // Function is f(x,y,z,w) = x^2 + y^2 + z^2 + w^2 |
| 337 | + cip::Vector4 f; |
| 338 | + f.resize(x.size()); |
| 339 | + for (size_t i = 0; i < x.size(); ++i) { |
| 340 | + f[i].resize(y.size()); |
| 341 | + for (size_t j = 0; j < y.size(); ++j) { |
| 342 | + f[i][j].resize(z.size()); |
| 343 | + for (size_t k = 0; k < z.size(); ++k) { |
| 344 | + f[i][j][k].resize(w.size()); |
| 345 | + for (size_t l = 0; l < w.size(); ++l) { |
| 346 | + // Quadratic function |
| 347 | + f[i][j][k][l] = x[i]*x[i] + y[j]*y[j] + z[k]*z[k] + w[l]*w[l]; |
| 348 | + } |
| 349 | + } |
| 350 | + } |
| 351 | + } |
| 352 | + |
| 353 | + // Create interpolator |
| 354 | + cip::LinearInterp4D<double> interp(x, y, z, w, f); |
| 355 | + |
| 356 | + // Test a few specific points without using fine grid |
| 357 | + // For interpolation at grid points, result should be exact |
| 358 | + EXPECT_DOUBLE_EQ(interp.eval(0.0, 0.0, 0.0, 0.0), 0.0); |
| 359 | + EXPECT_DOUBLE_EQ(interp.eval(1.0, 1.0, 1.0, 1.0), 4.0); |
| 360 | + EXPECT_DOUBLE_EQ(interp.eval(2.0, 2.0, 2.0, 2.0), 16.0); |
| 361 | +} |
0 commit comments