DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
test_Limiters.cpp
Go to the documentation of this file.
1/**
2 * @file test_Limiters.cpp
3 * @brief Unit tests for standalone limiter functions in CFV/Limiters.hpp.
4 *
5 * Tests cover:
6 * - PolynomialSquaredNorm<2> and <3> for all supported row counts
7 * - PolynomialDotProduct<2> for all supported row counts
8 * - FWBAP_L2_Biway: sign preservation, identical-input pass-through, NaN-free
9 * - FWBAP_L2_Cut_Biway: sign preservation with cutting
10 * - FMINMOD_Biway: classical minmod properties
11 * - FVanLeer_Biway: classical Van-Leer limiter properties
12 * - FWBAP_L2_Multiway: multi-stencil weighted averaging
13 * - FWBAP_L2_Multiway_Polynomial2D: polynomial-norm weighted multi-stencil
14 * - FWBAP_L2_Multiway_PolynomialOrth: orthogonal polynomial multi-stencil
15 * - FWBAP_L2_Biway_PolynomialNorm<2>: polynomial-norm biway
16 * - FMEMM_Biway_PolynomialNorm<2>: MEMM biway
17 * - FMEMM_Multiway_Polynomial2D: MEMM multi-stencil
18 * - FWBAP_L2_Biway_PolynomialOrth: orthogonal biway
19 */
20
21#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
22#include "doctest.h"
23
24#include "CFV/Limiters.hpp"
25
26#include <Eigen/Core>
27#include <cmath>
28#include <vector>
29
30using namespace DNDS;
31using namespace DNDS::CFV;
32
33// ===================================================================
34// PolynomialSquaredNorm
35// ===================================================================
36
37TEST_CASE("PolynomialSquaredNorm<2> with 2 rows (P1)")
38{
39 Eigen::ArrayXXd theta(2, 3);
40 theta << 1.0, 2.0, 3.0,
41 4.0, 5.0, 6.0;
42 // weight: all 1.0 for nRows=2
43 // result[j] = theta(0,j)^2 + theta(1,j)^2
44 auto result = PolynomialSquaredNorm<2>(theta);
45 CHECK(result.size() == 3);
46 CHECK(result(0) == doctest::Approx(1.0 + 16.0));
47 CHECK(result(1) == doctest::Approx(4.0 + 25.0));
48 CHECK(result(2) == doctest::Approx(9.0 + 36.0));
49}
50
51TEST_CASE("PolynomialSquaredNorm<2> with 3 rows (P2)")
52{
53 Eigen::ArrayXXd theta(3, 2);
54 theta << 2.0, 1.0,
55 3.0, 4.0,
56 5.0, 6.0;
57 // result[j] = theta(0,j)^2 + theta(1,j)^2 * 0.5 + theta(2,j)^2
58 auto result = PolynomialSquaredNorm<2>(theta);
59 CHECK(result.size() == 2);
60 CHECK(result(0) == doctest::Approx(4.0 + 9.0 * 0.5 + 25.0));
61 CHECK(result(1) == doctest::Approx(1.0 + 16.0 * 0.5 + 36.0));
62}
63
64TEST_CASE("PolynomialSquaredNorm<2> with 4 rows (P3)")
65{
66 Eigen::ArrayXXd theta(4, 1);
67 theta << 1.0, 2.0, 3.0, 4.0;
68 // result = 1 + 4*(1/3) + 9*(1/3) + 16
69 auto result = PolynomialSquaredNorm<2>(theta);
70 CHECK(result.size() == 1);
71 CHECK(result(0) == doctest::Approx(1.0 + 4.0 / 3.0 + 9.0 / 3.0 + 16.0));
72}
73
74TEST_CASE("PolynomialSquaredNorm<3> with 3 rows (P1)")
75{
76 Eigen::ArrayXXd theta(3, 2);
77 theta << 1.0, 2.0,
78 3.0, 4.0,
79 5.0, 6.0;
80 // uniform weight 1 for nRows=3
81 auto result = PolynomialSquaredNorm<3>(theta);
82 CHECK(result.size() == 2);
83 CHECK(result(0) == doctest::Approx(1.0 + 9.0 + 25.0));
84 CHECK(result(1) == doctest::Approx(4.0 + 16.0 + 36.0));
85}
86
87TEST_CASE("PolynomialSquaredNorm<3> with 6 rows (P2)")
88{
89 Eigen::ArrayXXd theta(6, 1);
90 theta << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0;
91 // first 3 weight 1, next 3 weight 0.5
92 auto result = PolynomialSquaredNorm<3>(theta);
93 CHECK(result.size() == 1);
94 CHECK(result(0) == doctest::Approx(
95 1.0 + 4.0 + 9.0 + 16.0 * 0.5 + 25.0 * 0.5 + 36.0 * 0.5));
96}
97
98TEST_CASE("PolynomialSquaredNorm<3> with 10 rows (P3)")
99{
100 Eigen::ArrayXXd theta(10, 1);
101 for (int i = 0; i < 10; i++)
102 theta(i, 0) = static_cast<real>(i + 1);
103 // first 3: w=1, next 6: w=1/3, last 1: w=1/6
105 for (int i = 0; i < 3; i++)
106 expected += theta(i, 0) * theta(i, 0);
107 for (int i = 3; i < 9; i++)
108 expected += theta(i, 0) * theta(i, 0) / 3.0;
109 expected += theta(9, 0) * theta(9, 0) / 6.0;
110 auto result = PolynomialSquaredNorm<3>(theta);
111 CHECK(result(0) == doctest::Approx(expected));
112}
113
114// ===================================================================
115// PolynomialDotProduct
116// ===================================================================
117
118TEST_CASE("PolynomialDotProduct<2> self-product equals PolynomialSquaredNorm")
119{
120 for (int nRows : {2, 3, 4})
121 {
122 CAPTURE(nRows);
123 Eigen::ArrayXXd theta(nRows, 3);
124 theta.setRandom();
125 auto normResult = PolynomialSquaredNorm<2>(theta);
126 auto dotResult = PolynomialDotProduct<2>(theta, theta);
127 for (int j = 0; j < 3; j++)
128 {
129 CAPTURE(j);
130 CHECK(dotResult(j) == doctest::Approx(normResult(j)).epsilon(1e-14));
131 }
132 }
133}
134
135TEST_CASE("PolynomialDotProduct<2> linearity")
136{
137 int nRows = 3;
138 Eigen::ArrayXXd a(nRows, 2), b(nRows, 2);
139 a << 1.0, 2.0,
140 3.0, 4.0,
141 5.0, 6.0;
142 b << 0.5, 1.5,
143 2.5, 3.5,
144 4.5, 5.5;
145 real alpha = 2.5;
146 // dot(alpha*a, b) == alpha * dot(a, b)
147 Eigen::ArrayXXd alphaA = alpha * a;
148 Eigen::ArrayXd left = PolynomialDotProduct<2>(alphaA, b);
149 Eigen::ArrayXd right = alpha * PolynomialDotProduct<2>(a, b);
150 for (int j = 0; j < 2; j++)
151 {
152 CAPTURE(j);
153 CHECK(left(j) == doctest::Approx(right(j)).epsilon(1e-13));
154 }
155}
156
157// ===================================================================
158// FMINMOD_Biway
159// ===================================================================
160
161TEST_CASE("FMINMOD_Biway: same-sign inputs")
162{
163 Eigen::ArrayXXd u1(2, 3), u2(2, 3), out(2, 3);
164 u1 << 1.0, 2.0, 5.0,
165 3.0, 4.0, 6.0;
166 u2 << 2.0, 1.0, 10.0,
167 6.0, 2.0, 3.0;
168 FMINMOD_Biway(u1, u2, out, 1.0);
169 // minmod(a,b) = sign(a)*min(|a|,|b|) when signs agree
170 CHECK(out(0, 0) == doctest::Approx(1.0));
171 CHECK(out(0, 1) == doctest::Approx(1.0));
172 CHECK(out(0, 2) == doctest::Approx(5.0));
173 CHECK(out(1, 0) == doctest::Approx(3.0));
174 CHECK(out(1, 1) == doctest::Approx(2.0));
175 CHECK(out(1, 2) == doctest::Approx(3.0));
176}
177
178TEST_CASE("FMINMOD_Biway: opposite-sign inputs produce zero")
179{
180 Eigen::ArrayXXd u1(1, 4), u2(1, 4), out(1, 4);
181 u1 << 1.0, -1.0, 3.0, -5.0;
182 u2 << -2.0, 2.0, -0.5, 7.0;
183 FMINMOD_Biway(u1, u2, out, 1.0);
184 for (int j = 0; j < 4; j++)
185 {
186 CAPTURE(j);
187 CHECK(out(0, j) == doctest::Approx(0.0));
188 }
189}
190
191TEST_CASE("FMINMOD_Biway: zero input")
192{
193 Eigen::ArrayXXd u1(1, 2), u2(1, 2), out(1, 2);
194 u1 << 0.0, 5.0;
195 u2 << 3.0, 0.0;
196 FMINMOD_Biway(u1, u2, out, 1.0);
197 CHECK(out(0, 0) == doctest::Approx(0.0));
198 CHECK(out(0, 1) == doctest::Approx(0.0));
199}
200
201// ===================================================================
202// FVanLeer_Biway
203// ===================================================================
204
205TEST_CASE("FVanLeer_Biway: same-sign inputs")
206{
207 Eigen::ArrayXXd u1(1, 2), u2(1, 2), out(1, 2);
208 u1 << 2.0, -3.0;
209 u2 << 4.0, -6.0;
210 FVanLeer_Biway(u1, u2, out, 1.0);
211 // VanLeer(a,b) = (sign(a)+sign(b)) * |a*b| / (|a+b| + eps)
212 // For same-sign: 2 * |a*b| / (|a+b| + eps) ~ 2*|ab|/|a+b|
213 // u1=2,u2=4: 2*8/6 = 8/3
214 CHECK(out(0, 0) == doctest::Approx(8.0 / 3.0).epsilon(1e-10));
215 // u1=-3,u2=-6: 2*18/9 = 4.0
216 CHECK(out(0, 1) == doctest::Approx(-4.0).epsilon(1e-10));
217}
218
219TEST_CASE("FVanLeer_Biway: opposite-sign produces zero")
220{
221 Eigen::ArrayXXd u1(1, 2), u2(1, 2), out(1, 2);
222 u1 << 3.0, -5.0;
223 u2 << -2.0, 7.0;
224 FVanLeer_Biway(u1, u2, out, 1.0);
225 CHECK(out(0, 0) == doctest::Approx(0.0).epsilon(1e-10));
226 CHECK(out(0, 1) == doctest::Approx(0.0).epsilon(1e-10));
227}
228
229TEST_CASE("FVanLeer_Biway: equal inputs return same value")
230{
231 Eigen::ArrayXXd u1(1, 2), u2(1, 2), out(1, 2);
232 u1 << 5.0, -3.0;
233 u2 = u1;
234 FVanLeer_Biway(u1, u2, out, 1.0);
235 // VanLeer(a,a) = 2*a^2 / (2*|a|) = |a| * sign(a) = a
236 CHECK(out(0, 0) == doctest::Approx(5.0).epsilon(1e-10));
237 CHECK(out(0, 1) == doctest::Approx(-3.0).epsilon(1e-10));
238}
239
240// ===================================================================
241// FWBAP_L2_Biway
242// ===================================================================
243
244TEST_CASE("FWBAP_L2_Biway: identical inputs pass through")
245{
246 Eigen::ArrayXXd u1(2, 3), u2(2, 3), out(2, 3);
247 u1.setRandom();
248 u2 = u1;
249 FWBAP_L2_Biway(u1, u2, out, 1.0);
250 for (int i = 0; i < 2; i++)
251 for (int j = 0; j < 3; j++)
252 {
253 CAPTURE(i);
254 CAPTURE(j);
255 CHECK(out(i, j) == doctest::Approx(u1(i, j)).epsilon(1e-10));
256 }
257}
258
259TEST_CASE("FWBAP_L2_Biway: no NaN for random inputs")
260{
261 Eigen::ArrayXXd u1(3, 5), u2(3, 5), out(3, 5);
262 u1.setRandom();
263 u2.setRandom();
264 FWBAP_L2_Biway(u1, u2, out, 1.0);
265 CHECK_FALSE(out.hasNaN());
266}
267
268TEST_CASE("FWBAP_L2_Biway: output bounded by inputs for same-sign")
269{
270 // For same-sign inputs, WBAP output should not exceed the extremes
271 Eigen::ArrayXXd u1(1, 100), u2(1, 100), out(1, 100);
272 u1.setRandom();
273 u1 = u1.abs() + 0.1; // all positive
274 u2.setRandom();
275 u2 = u2.abs() + 0.1; // all positive
276 FWBAP_L2_Biway(u1, u2, out, 1.0);
277 for (int j = 0; j < 100; j++)
278 {
279 CAPTURE(j);
280 // Output should be non-negative
281 CHECK(out(0, j) >= -1e-10);
282 }
283}
284
285// ===================================================================
286// FWBAP_L2_Cut_Biway
287// ===================================================================
288
289TEST_CASE("FWBAP_L2_Cut_Biway: opposite-sign cut to zero")
290{
291 Eigen::ArrayXXd u1(1, 3), u2(1, 3), out(1, 3);
292 u1 << 1.0, -2.0, 3.0;
293 u2 << -1.0, 2.0, -3.0;
294 FWBAP_L2_Cut_Biway(u1, u2, out, 1.0);
295 for (int j = 0; j < 3; j++)
296 {
297 CAPTURE(j);
298 CHECK(out(0, j) == doctest::Approx(0.0).epsilon(1e-10));
299 }
300}
301
302TEST_CASE("FWBAP_L2_Cut_Biway: no NaN")
303{
304 Eigen::ArrayXXd u1(2, 4), u2(2, 4), out(2, 4);
305 u1.setRandom();
306 u2.setRandom();
307 FWBAP_L2_Cut_Biway(u1, u2, out, 1.0);
308 CHECK_FALSE(out.hasNaN());
309}
310
311// ===================================================================
312// FWBAP_L2_Multiway
313// ===================================================================
314
315TEST_CASE("FWBAP_L2_Multiway: all identical inputs pass through")
316{
317 Eigen::ArrayXXd u0(2, 3);
318 u0.setRandom();
319 std::vector<Eigen::ArrayXXd> uOthers = {u0, u0, u0, u0};
320 Eigen::ArrayXXd out;
321 out.resizeLike(u0);
322 FWBAP_L2_Multiway(uOthers, 4, out, 1.0);
323 for (int i = 0; i < 2; i++)
324 for (int j = 0; j < 3; j++)
325 {
326 CAPTURE(i);
327 CAPTURE(j);
328 CHECK(out(i, j) == doctest::Approx(u0(i, j)).epsilon(1e-8));
329 }
330}
331
332TEST_CASE("FWBAP_L2_Multiway: no NaN for random inputs")
333{
334 std::vector<Eigen::ArrayXXd> uOthers(5);
335 for (auto &u : uOthers)
336 {
337 u.resize(3, 4);
338 u.setRandom();
339 }
340 Eigen::ArrayXXd out;
341 out.resizeLike(uOthers[0]);
342 FWBAP_L2_Multiway(uOthers, 5, out, 1.0);
343 CHECK_FALSE(out.hasNaN());
344}
345
346// ===================================================================
347// FWBAP_L2_Multiway_Polynomial2D
348// ===================================================================
349
350TEST_CASE("FWBAP_L2_Multiway_Polynomial2D: all identical pass through")
351{
352 Eigen::ArrayXXd u0(2, 3);
353 u0.setRandom();
354 std::vector<Eigen::ArrayXXd> uOthers = {u0, u0, u0};
355 Eigen::ArrayXXd out;
356 out.resizeLike(u0);
357 FWBAP_L2_Multiway_Polynomial2D(uOthers, 3, out, 1.0);
358 for (int i = 0; i < 2; i++)
359 for (int j = 0; j < 3; j++)
360 {
361 CAPTURE(i);
362 CAPTURE(j);
363 CHECK(out(i, j) == doctest::Approx(u0(i, j)).epsilon(1e-8));
364 }
365}
366
367TEST_CASE("FWBAP_L2_Multiway_Polynomial2D: no NaN for random inputs (nRows=2,3,4)")
368{
369 for (int nRows : {2, 3, 4})
370 {
371 CAPTURE(nRows);
372 std::vector<Eigen::ArrayXXd> uOthers(4);
373 for (auto &u : uOthers)
374 {
375 u.resize(nRows, 3);
376 u.setRandom();
377 }
378 Eigen::ArrayXXd out;
379 out.resizeLike(uOthers[0]);
380 FWBAP_L2_Multiway_Polynomial2D(uOthers, 4, out, 1.0);
381 CHECK_FALSE(out.hasNaN());
382 }
383}
384
385// ===================================================================
386// FMEMM_Multiway_Polynomial2D
387// ===================================================================
388
389TEST_CASE("FMEMM_Multiway_Polynomial2D: center input unchanged when smallest")
390{
391 // If center has the smallest polynomial norm, MEMM should leave it alone
392 Eigen::ArrayXXd center(2, 2);
393 center << 0.1, 0.2,
394 0.1, 0.2;
395 std::vector<Eigen::ArrayXXd> uOthers(3);
396 for (auto &u : uOthers)
397 {
398 u.resize(2, 2);
399 u.setRandom();
400 u *= 10.0; // make neighbors much larger
401 }
402 Eigen::ArrayXXd out;
403 out.resizeLike(center);
404 FMEMM_Multiway_Polynomial2D(center, uOthers, 3, out, 1.0);
405 CHECK_FALSE(out.hasNaN());
406 // When center is smallest, ifReplace=0 so replaceFactor=1 and output=center
407 for (int i = 0; i < 2; i++)
408 for (int j = 0; j < 2; j++)
409 {
410 CAPTURE(i);
411 CAPTURE(j);
412 CHECK(out(i, j) == doctest::Approx(center(i, j)).epsilon(1e-8));
413 }
414}
415
416TEST_CASE("FMEMM_Multiway_Polynomial2D: no NaN for random inputs")
417{
418 Eigen::ArrayXXd center(3, 4);
419 center.setRandom();
420 std::vector<Eigen::ArrayXXd> uOthers(3);
421 for (auto &u : uOthers)
422 {
423 u.resize(3, 4);
424 u.setRandom();
425 }
426 Eigen::ArrayXXd out;
427 out.resizeLike(center);
428 FMEMM_Multiway_Polynomial2D(center, uOthers, 3, out, 1.0);
429 CHECK_FALSE(out.hasNaN());
430}
431
432// ===================================================================
433// FWBAP_L2_Multiway_PolynomialOrth
434// ===================================================================
435
436TEST_CASE("FWBAP_L2_Multiway_PolynomialOrth: all identical pass through")
437{
438 Eigen::ArrayXXd u0(3, 2);
439 u0.setRandom();
440 std::vector<Eigen::ArrayXXd> uOthers = {u0, u0, u0};
441 Eigen::ArrayXXd out;
442 out.resizeLike(u0);
443 FWBAP_L2_Multiway_PolynomialOrth(uOthers, 3, out, 1.0);
444 for (int i = 0; i < 3; i++)
445 for (int j = 0; j < 2; j++)
446 {
447 CAPTURE(i);
448 CAPTURE(j);
449 CHECK(out(i, j) == doctest::Approx(u0(i, j)).epsilon(1e-8));
450 }
451}
452
453TEST_CASE("FWBAP_L2_Multiway_PolynomialOrth: no NaN")
454{
455 std::vector<Eigen::ArrayXXd> uOthers(4);
456 for (auto &u : uOthers)
457 {
458 u.resize(4, 3);
459 u.setRandom();
460 }
461 Eigen::ArrayXXd out;
462 out.resizeLike(uOthers[0]);
463 FWBAP_L2_Multiway_PolynomialOrth(uOthers, 4, out, 1.0);
464 CHECK_FALSE(out.hasNaN());
465}
466
467// ===================================================================
468// FWBAP_L2_Biway_PolynomialNorm<2, nVarsFixed>
469// ===================================================================
470
471TEST_CASE("FWBAP_L2_Biway_PolynomialNorm<2,1>: identical inputs pass through")
472{
473 using ArrT = Eigen::Array<real, Eigen::Dynamic, 1>;
474 ArrT u1(2, 1), u2(2, 1), out(2, 1);
475 u1 << 3.0, 4.0;
476 u2 = u1;
477 FWBAP_L2_Biway_PolynomialNorm<2, 1>(u1, u2, out, 1.0);
478 CHECK(out(0) == doctest::Approx(u1(0)).epsilon(1e-8));
479 CHECK(out(1) == doctest::Approx(u1(1)).epsilon(1e-8));
480}
481
482TEST_CASE("FWBAP_L2_Biway_PolynomialNorm<2,Eigen::Dynamic>: no NaN")
483{
484 Eigen::ArrayXXd u1(3, 4), u2(3, 4), out(3, 4);
485 u1.setRandom();
486 u2.setRandom();
487 FWBAP_L2_Biway_PolynomialNorm<2, Eigen::Dynamic>(u1, u2, out, 1.0);
488 CHECK_FALSE(out.hasNaN());
489}
490
491TEST_CASE("FWBAP_L2_Biway_PolynomialNorm<3,Eigen::Dynamic>: no NaN for 3D dims")
492{
493 for (int nRows : {3, 6, 10})
494 {
495 CAPTURE(nRows);
496 Eigen::ArrayXXd u1(nRows, 2), u2(nRows, 2), out(nRows, 2);
497 u1.setRandom();
498 u2.setRandom();
499 FWBAP_L2_Biway_PolynomialNorm<3, Eigen::Dynamic>(u1, u2, out, 1.0);
500 CHECK_FALSE(out.hasNaN());
501 }
502}
503
504// ===================================================================
505// FMEMM_Biway_PolynomialNorm<2, nVarsFixed>
506// ===================================================================
507
508TEST_CASE("FMEMM_Biway_PolynomialNorm<2,Eigen::Dynamic>: u2 smaller returns u2")
509{
510 // When u2 has smaller polynomial norm, MEMM should return u2
511 Eigen::ArrayXXd u1(2, 2), u2(2, 2), out(2, 2);
512 u1 << 10.0, 20.0,
513 10.0, 20.0;
514 u2 << 0.1, 0.2,
515 0.1, 0.2;
516 FMEMM_Biway_PolynomialNorm<2, Eigen::Dynamic>(u1, u2, out, 1.0);
517 CHECK_FALSE(out.hasNaN());
518 // When u1 is much larger, the limiter should reduce toward u2
519 // Check output is closer to u2 than to u1
520 real dist_to_u2 = (out - u2).matrix().norm();
521 real dist_to_u1 = (out - u1).matrix().norm();
522 CHECK(dist_to_u2 < dist_to_u1);
523}
524
525TEST_CASE("FMEMM_Biway_PolynomialNorm<2,Eigen::Dynamic>: no NaN")
526{
527 Eigen::ArrayXXd u1(4, 3), u2(4, 3), out(4, 3);
528 u1.setRandom();
529 u2.setRandom();
530 FMEMM_Biway_PolynomialNorm<2, Eigen::Dynamic>(u1, u2, out, 1.0);
531 CHECK_FALSE(out.hasNaN());
532}
533
534// ===================================================================
535// FWBAP_L2_Biway_PolynomialOrth
536// ===================================================================
537
538TEST_CASE("FWBAP_L2_Biway_PolynomialOrth: identical inputs pass through")
539{
540 Eigen::ArrayXXd u1(3, 2), u2(3, 2), out(3, 2);
541 u1.setRandom();
542 u2 = u1;
543 FWBAP_L2_Biway_PolynomialOrth(u1, u2, out, 1.0);
544 for (int i = 0; i < 3; i++)
545 for (int j = 0; j < 2; j++)
546 {
547 CAPTURE(i);
548 CAPTURE(j);
549 CHECK(out(i, j) == doctest::Approx(u1(i, j)).epsilon(1e-8));
550 }
551}
552
553TEST_CASE("FWBAP_L2_Biway_PolynomialOrth: no NaN")
554{
555 Eigen::ArrayXXd u1(4, 5), u2(4, 5), out(4, 5);
556 u1.setRandom();
557 u2.setRandom();
558 FWBAP_L2_Biway_PolynomialOrth(u1, u2, out, 1.0);
559 CHECK_FALSE(out.hasNaN());
560}
561
562// ===================================================================
563// Cross-consistency: FMINMOD is most restrictive
564// ===================================================================
565
566TEST_CASE("Limiter ordering: FMINMOD output <= FWBAP output for same-sign")
567{
568 Eigen::ArrayXXd u1(1, 100), u2(1, 100), outMM(1, 100), outWBAP(1, 100);
569 u1.setRandom();
570 u1 = u1.abs() + 0.01;
571 u2.setRandom();
572 u2 = u2.abs() + 0.01;
573 FMINMOD_Biway(u1, u2, outMM, 1.0);
574 FWBAP_L2_Biway(u1, u2, outWBAP, 1.0);
575 // MINMOD is the most restrictive TVD limiter
576 for (int j = 0; j < 100; j++)
577 {
578 CAPTURE(j);
579 CHECK(outMM(0, j) <= outWBAP(0, j) + 1e-12);
580 }
581}
582
583// ===================================================================
584// Edge case: near-zero inputs
585// ===================================================================
586
587TEST_CASE("All limiters handle near-zero inputs without NaN")
588{
589 Eigen::ArrayXXd u1(2, 3), u2(2, 3);
590 u1.setConstant(1e-300);
591 u2.setConstant(1e-300);
592
593 Eigen::ArrayXXd out(2, 3);
594
595 SUBCASE("FMINMOD")
596 {
597 FMINMOD_Biway(u1, u2, out, 1.0);
598 CHECK_FALSE(out.hasNaN());
599 }
600 SUBCASE("FVanLeer")
601 {
602 FVanLeer_Biway(u1, u2, out, 1.0);
603 CHECK_FALSE(out.hasNaN());
604 }
605 SUBCASE("FWBAP_L2_Biway")
606 {
607 FWBAP_L2_Biway(u1, u2, out, 1.0);
608 CHECK_FALSE(out.hasNaN());
609 }
610 SUBCASE("FWBAP_L2_Cut_Biway")
611 {
612 FWBAP_L2_Cut_Biway(u1, u2, out, 1.0);
613 CHECK_FALSE(out.hasNaN());
614 }
615 SUBCASE("FWBAP_L2_Biway_PolynomialNorm<2>")
616 {
617 FWBAP_L2_Biway_PolynomialNorm<2, Eigen::Dynamic>(u1, u2, out, 1.0);
618 CHECK_FALSE(out.hasNaN());
619 }
620 SUBCASE("FWBAP_L2_Biway_PolynomialOrth")
621 {
622 FWBAP_L2_Biway_PolynomialOrth(u1, u2, out, 1.0);
623 CHECK_FALSE(out.hasNaN());
624 }
625}
void FWBAP_L2_Cut_Biway(const Tin1 &u1, const Tin2 &u2, Tout &uOut, real n)
Definition Limiters.hpp:483
void FWBAP_L2_Multiway(const TinOthers &uOthers, int Nother, Tout &uOut, real n1=1.0)
input vector<Eigen::Array-like>
Definition Limiters.hpp:361
void FMINMOD_Biway(const Tin1 &u1, const Tin2 &u2, Tout &uOut, real n)
input eigen arrays
Definition Limiters.hpp:503
void FWBAP_L2_Biway_PolynomialOrth(const Tin1 &u1, const Tin2 &u2, Tout &uOut, real n)
Definition Limiters.hpp:577
void FVanLeer_Biway(const Tin1 &u1, const Tin2 &u2, Tout &uOut, real n)
input eigen arrays
Definition Limiters.hpp:512
void FWBAP_L2_Biway(const Tin1 &u1, const Tin2 &u2, Tout &uOut, real n)
input eigen arrays
Definition Limiters.hpp:432
the host side operators are provided as implemented
double real
Canonical floating-point scalar used throughout DNDSR (double precision).
Definition Defines.hpp:105
tVec b(NCells)
real alpha
CHECK(result.size()==3)
real expected
auto result
TEST_CASE("3D: VFV P2 HQM error < P1 on sinCos3D")