DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
test_ArrayDOF.cpp
Go to the documentation of this file.
1/**
2 * @file test_ArrayDOF.cpp
3 * @brief Comprehensive doctest-based unit tests for DNDS::ArrayDof
4 * (degree-of-freedom array) vector-space operations.
5 *
6 * Run under mpirun with 1, 2, and 4 ranks. All MPI-global reductions
7 * (norm2, dot, min, max, sum, componentWiseNorm1) are tested with
8 * rank-aware expected values that scale correctly at any process count.
9 *
10 * @see @ref dnds_unit_tests for the full test-suite overview.
11 * @test setConstant, operator+= (scalar/array/matrix), operator-=,
12 * operator*= (scalar/element-wise/matrix), operator/=, addTo,
13 * norm2, dot, min, max, sum, componentWiseNorm1, operator= (copy),
14 * clone, scalar-array multiply, identity dot(x,x)==norm2(x)^2.
15 */
16
17#define DOCTEST_CONFIG_IMPLEMENT
18#include "doctest.h"
19#include "DNDS/ArrayDOF.hpp"
20#include <cmath>
21
22using namespace DNDS;
23
24int main(int argc, char **argv)
25{
26 MPI_Init(&argc, &argv);
27 doctest::Context ctx;
28 ctx.applyCommandLine(argc, argv);
29 int res = ctx.run();
30 MPI_Finalize();
31 return res;
32}
33
34// ---------------------------------------------------------------------------
35// Helpers
36// ---------------------------------------------------------------------------
37
38static MPIInfo worldMPI()
39{
41 mpi.setWorld();
42 return mpi;
43}
44
45/// Build an ArrayDof<M,N> with father-only storage (no ghost/son data).
46/// The son is allocated with zero rows so that the pair is valid for
47/// vector-space operations which only touch father data.
48template <int M, int N>
49static ArrayDof<M, N> makeDof(const MPIInfo &mpi, DNDS::index nCells,
50 DNDS::rowsize mRow = M, DNDS::rowsize nCol = N)
51{
53 dof.InitPair("dof::arr", mpi);
54 dof.father->Resize(nCells, mRow, nCol);
55 dof.son->Resize(0, mRow, nCol);
56 dof.TransAttach();
57 return dof;
58}
59
60// ---------------------------------------------------------------------------
61TEST_CASE("ArrayDOF setup and setConstant")
62{
63 MPIInfo mpi = worldMPI();
64 constexpr DNDS::index N = 100;
65
66 auto dof = makeDof<5, 1>(mpi, N);
67
68 SUBCASE("setConstant with scalar")
69 {
70 dof.setConstant(2.0);
71 for (DNDS::index i = 0; i < dof.father->Size(); i++)
72 {
73 auto mat = dof[i];
74 for (int r = 0; r < mat.rows(); r++)
75 CHECK(mat(r, 0) == doctest::Approx(2.0));
76 }
77 }
78
79 SUBCASE("setConstant with Eigen matrix")
80 {
81 Eigen::Matrix<real, 5, 1> v;
82 v << 1.0, 2.0, 3.0, 4.0, 5.0;
83 dof.setConstant(v);
84
85 for (DNDS::index i = 0; i < dof.father->Size(); i++)
86 {
87 auto mat = dof[i];
88 CHECK(mat(0, 0) == doctest::Approx(1.0));
89 CHECK(mat(1, 0) == doctest::Approx(2.0));
90 CHECK(mat(2, 0) == doctest::Approx(3.0));
91 CHECK(mat(3, 0) == doctest::Approx(4.0));
92 CHECK(mat(4, 0) == doctest::Approx(5.0));
93 }
94 }
95}
96
97// ---------------------------------------------------------------------------
98TEST_CASE("ArrayDOF operator+= scalar and array")
99{
100 MPIInfo mpi = worldMPI();
101 constexpr DNDS::index N = 80;
102
103 auto dof1 = makeDof<5, 1>(mpi, N);
104 dof1.setConstant(1.0);
105
106 SUBCASE("+= scalar")
107 {
108 dof1 += 2.0;
109
110 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
111 {
112 auto mat = dof1[i];
113 for (int r = 0; r < mat.rows(); r++)
114 CHECK(mat(r, 0) == doctest::Approx(3.0));
115 }
116 }
117
118 SUBCASE("+= another ArrayDof")
119 {
120 dof1 += 2.0; // dof1 is now 3.0
121
122 auto dof2 = makeDof<5, 1>(mpi, N);
123 dof2.setConstant(10.0);
124
125 dof1 += dof2;
126
127 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
128 {
129 auto mat = dof1[i];
130 for (int r = 0; r < mat.rows(); r++)
131 CHECK(mat(r, 0) == doctest::Approx(13.0));
132 }
133 }
134
135 SUBCASE("+= Eigen matrix")
136 {
137 Eigen::Matrix<real, 5, 1> v;
138 v << 10.0, 20.0, 30.0, 40.0, 50.0;
139 dof1 += v;
140
141 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
142 {
143 auto mat = dof1[i];
144 CHECK(mat(0, 0) == doctest::Approx(11.0));
145 CHECK(mat(1, 0) == doctest::Approx(21.0));
146 CHECK(mat(2, 0) == doctest::Approx(31.0));
147 CHECK(mat(3, 0) == doctest::Approx(41.0));
148 CHECK(mat(4, 0) == doctest::Approx(51.0));
149 }
150 }
151}
152
153// ---------------------------------------------------------------------------
154TEST_CASE("ArrayDOF operator-= and operator*=")
155{
156 MPIInfo mpi = worldMPI();
157 constexpr DNDS::index N = 60;
158
159 auto dof1 = makeDof<5, 1>(mpi, N);
160 auto dof2 = makeDof<5, 1>(mpi, N);
161 dof1.setConstant(10.0);
162 dof2.setConstant(3.0);
163
164 SUBCASE("-= array then *= scalar")
165 {
166 dof1 -= dof2;
167
168 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
169 {
170 auto mat = dof1[i];
171 for (int r = 0; r < mat.rows(); r++)
172 CHECK(mat(r, 0) == doctest::Approx(7.0));
173 }
174
175 dof1 *= 2.0;
176
177 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
178 {
179 auto mat = dof1[i];
180 for (int r = 0; r < mat.rows(); r++)
181 CHECK(mat(r, 0) == doctest::Approx(14.0));
182 }
183 }
184
185 SUBCASE("*= by 1.0 is identity")
186 {
187 dof1 *= 1.0;
188
189 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
190 {
191 auto mat = dof1[i];
192 for (int r = 0; r < mat.rows(); r++)
193 CHECK(mat(r, 0) == doctest::Approx(10.0));
194 }
195 }
196}
197
198// ---------------------------------------------------------------------------
199TEST_CASE("ArrayDOF addTo")
200{
201 MPIInfo mpi = worldMPI();
202 constexpr DNDS::index N = 50;
203
204 auto dof1 = makeDof<5, 1>(mpi, N);
205 auto dof2 = makeDof<5, 1>(mpi, N);
206 dof1.setConstant(1.0);
207 dof2.setConstant(5.0);
208
209 // dof1 += dof2 * 3.0 => 1.0 + 5.0*3.0 = 16.0
210 dof1.addTo(dof2, 3.0);
211
212 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
213 {
214 auto mat = dof1[i];
215 for (int r = 0; r < mat.rows(); r++)
216 CHECK(mat(r, 0) == doctest::Approx(16.0));
217 }
218}
219
220// ---------------------------------------------------------------------------
221TEST_CASE("ArrayDOF norm2")
222{
223 MPIInfo mpi = worldMPI();
224 constexpr DNDS::index N = 100;
225
226 SUBCASE("uniform value")
227 {
228 // ArrayDof<1,1>: one scalar per cell.
229 // All set to 1.0. Squared norm = N * size, so norm2 = sqrt(N*size).
230 auto dof = makeDof<1, 1>(mpi, N);
231 dof.setConstant(1.0);
232
233 real n2 = dof.norm2();
234 real expected = std::sqrt(static_cast<real>(N) * mpi.size);
235 CHECK(n2 == doctest::Approx(expected));
236 }
237
238 SUBCASE("multi-component uniform")
239 {
240 // ArrayDof<5,1>: 5 components per cell, all 1.0.
241 // Each cell contributes 5*1^2 = 5 to the squared norm.
242 // Global: 5 * N * size => norm2 = sqrt(5*N*size).
243 auto dof = makeDof<5, 1>(mpi, N);
244 dof.setConstant(1.0);
245
246 real n2 = dof.norm2();
247 real expected = std::sqrt(5.0 * N * mpi.size);
248 CHECK(n2 == doctest::Approx(expected));
249 }
250
251 SUBCASE("non-uniform values")
252 {
253 // ArrayDof<1,1>, each cell = rank + 1.
254 auto dof = makeDof<1, 1>(mpi, N);
255 real val = static_cast<real>(mpi.rank + 1);
256 dof.setConstant(val);
257
258 // Sum of squares across all ranks:
259 // Each rank r contributes N * (r+1)^2.
260 real globalSqSum = 0;
261 for (MPI_int r = 0; r < mpi.size; r++)
262 globalSqSum += N * static_cast<real>((r + 1) * (r + 1));
263
264 real n2 = dof.norm2();
265 CHECK(n2 == doctest::Approx(std::sqrt(globalSqSum)));
266 }
267
268 SUBCASE("norm2 difference overload")
269 {
270 auto dof1 = makeDof<1, 1>(mpi, N);
271 auto dof2 = makeDof<1, 1>(mpi, N);
272 dof1.setConstant(5.0);
273 dof2.setConstant(2.0);
274
275 // norm2(dof1, dof2) = sqrt(sum((5-2)^2)) = 3 * sqrt(N*size)
276 real n2 = dof1.norm2(dof2);
277 real expected = 3.0 * std::sqrt(static_cast<real>(N) * mpi.size);
278 CHECK(n2 == doctest::Approx(expected));
279 }
280}
281
282// ---------------------------------------------------------------------------
283TEST_CASE("ArrayDOF dot")
284{
285 MPIInfo mpi = worldMPI();
286 constexpr DNDS::index N = 100;
287
288 SUBCASE("scalar dof")
289 {
290 auto dof1 = makeDof<1, 1>(mpi, N);
291 auto dof2 = makeDof<1, 1>(mpi, N);
292 dof1.setConstant(2.0);
293 dof2.setConstant(3.0);
294
295 // dot = sum_i (2*3) = 6 * N * size
296 real d = dof1.dot(dof2);
297 real expected = 6.0 * N * mpi.size;
298 CHECK(d == doctest::Approx(expected));
299 }
300
301 SUBCASE("multi-component dof")
302 {
303 auto dof1 = makeDof<5, 1>(mpi, N);
304 auto dof2 = makeDof<5, 1>(mpi, N);
305 dof1.setConstant(2.0);
306 dof2.setConstant(3.0);
307
308 // Each cell contributes 5 * (2*3) = 30.
309 // Global: 30 * N * size.
310 real d = dof1.dot(dof2);
311 real expected = 30.0 * N * mpi.size;
312 CHECK(d == doctest::Approx(expected));
313 }
314}
315
316// ---------------------------------------------------------------------------
317TEST_CASE("ArrayDOF min and max")
318{
319 MPIInfo mpi = worldMPI();
320 constexpr DNDS::index N = 50;
321
322 auto dof = makeDof<3, 1>(mpi, N);
323 dof.setConstant(0.0);
324
325 // Rank 0 writes a very negative value into its first cell.
326 if (mpi.rank == 0)
327 dof[0].setConstant(-100.0);
328
329 // Last rank writes a very large value into its last cell.
330 if (mpi.rank == mpi.size - 1)
331 dof[N - 1].setConstant(999.0);
332
333 real gmin = dof.min();
334 real gmax = dof.max();
335
336 CHECK(gmin == doctest::Approx(-100.0));
337 CHECK(gmax == doctest::Approx(999.0));
338}
339
340// ---------------------------------------------------------------------------
341TEST_CASE("ArrayDOF sum")
342{
343 MPIInfo mpi = worldMPI();
344 constexpr DNDS::index N = 100;
345
346 // ArrayDof<1,1>: one scalar per cell, all set to 1.0.
347 auto dof = makeDof<1, 1>(mpi, N);
348 dof.setConstant(1.0);
349
350 real s = dof.sum();
351 real expected = static_cast<real>(N) * mpi.size;
352 CHECK(s == doctest::Approx(expected));
353}
354
355// ---------------------------------------------------------------------------
356TEST_CASE("ArrayDOF componentWiseNorm1")
357{
358 MPIInfo mpi = worldMPI();
359 constexpr DNDS::index N = 100;
360
361 auto dof = makeDof<3, 1>(mpi, N);
362
363 // Set per-component values: comp0 = 1, comp1 = -2, comp2 = 3.
364 Eigen::Matrix<real, 3, 1> v;
365 v << 1.0, -2.0, 3.0;
366 dof.setConstant(v);
367
368 auto norm1 = dof.componentWiseNorm1();
369
370 // L1 norm per component across all ranks: |val| * N * size.
371 real totalCells = static_cast<real>(N) * mpi.size;
372 CHECK(norm1(0, 0) == doctest::Approx(1.0 * totalCells));
373 CHECK(norm1(1, 0) == doctest::Approx(2.0 * totalCells));
374 CHECK(norm1(2, 0) == doctest::Approx(3.0 * totalCells));
375}
376
377// ---------------------------------------------------------------------------
378TEST_CASE("ArrayDOF componentWiseNorm1 difference")
379{
380 MPIInfo mpi = worldMPI();
381 constexpr DNDS::index N = 80;
382
383 auto dof1 = makeDof<3, 1>(mpi, N);
384 auto dof2 = makeDof<3, 1>(mpi, N);
385
386 Eigen::Matrix<real, 3, 1> v1, v2;
387 v1 << 5.0, 10.0, -3.0;
388 v2 << 2.0, 7.0, 1.0;
389 dof1.setConstant(v1);
390 dof2.setConstant(v2);
391
392 // componentWiseNorm1(dof2) = sum |dof1 - dof2| per component.
393 // diffs: |3|, |3|, |4|
394 auto norm1 = dof1.componentWiseNorm1(dof2);
395
396 real totalCells = static_cast<real>(N) * mpi.size;
397 CHECK(norm1(0, 0) == doctest::Approx(3.0 * totalCells));
398 CHECK(norm1(1, 0) == doctest::Approx(3.0 * totalCells));
399 CHECK(norm1(2, 0) == doctest::Approx(4.0 * totalCells));
400}
401
402// ---------------------------------------------------------------------------
403TEST_CASE("ArrayDOF element-wise multiply and divide")
404{
405 MPIInfo mpi = worldMPI();
406 constexpr DNDS::index N = 50;
407
408 auto dof1 = makeDof<3, 1>(mpi, N);
409 auto dof2 = makeDof<3, 1>(mpi, N);
410
411 Eigen::Matrix<real, 3, 1> v1, v2;
412 v1 << 6.0, 8.0, 10.0;
413 v2 << 2.0, 4.0, 5.0;
414 dof1.setConstant(v1);
415 dof2.setConstant(v2);
416
417 SUBCASE("*= array (element-wise)")
418 {
419 dof1 *= dof2;
420
421 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
422 {
423 auto mat = dof1[i];
424 CHECK(mat(0, 0) == doctest::Approx(12.0));
425 CHECK(mat(1, 0) == doctest::Approx(32.0));
426 CHECK(mat(2, 0) == doctest::Approx(50.0));
427 }
428 }
429
430 SUBCASE("/= array (element-wise)")
431 {
432 dof1 /= dof2;
433
434 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
435 {
436 auto mat = dof1[i];
437 CHECK(mat(0, 0) == doctest::Approx(3.0));
438 CHECK(mat(1, 0) == doctest::Approx(2.0));
439 CHECK(mat(2, 0) == doctest::Approx(2.0));
440 }
441 }
442
443 SUBCASE("*= Eigen matrix (element-wise)")
444 {
445 Eigen::Matrix<real, 3, 1> scale;
446 scale << 0.5, 0.25, 0.1;
447 dof1 *= scale;
448
449 for (DNDS::index i = 0; i < dof1.father->Size(); i++)
450 {
451 auto mat = dof1[i];
452 CHECK(mat(0, 0) == doctest::Approx(3.0));
453 CHECK(mat(1, 0) == doctest::Approx(2.0));
454 CHECK(mat(2, 0) == doctest::Approx(1.0));
455 }
456 }
457}
458
459// ---------------------------------------------------------------------------
460TEST_CASE("ArrayDOF operator= (copy values)")
461{
462 MPIInfo mpi = worldMPI();
463 constexpr DNDS::index N = 40;
464
465 auto dof1 = makeDof<5, 1>(mpi, N);
466 auto dof2 = makeDof<5, 1>(mpi, N);
467
468 Eigen::Matrix<real, 5, 1> v;
469 v << 1.0, 2.0, 3.0, 4.0, 5.0;
470 dof1.setConstant(v);
471 dof2.setConstant(0.0);
472
473 // Copy values from dof1 into dof2.
474 dof2 = dof1;
475
476 // Verify dof2 now has dof1's values.
477 for (DNDS::index i = 0; i < dof2.father->Size(); i++)
478 {
479 auto mat = dof2[i];
480 CHECK(mat(0, 0) == doctest::Approx(1.0));
481 CHECK(mat(1, 0) == doctest::Approx(2.0));
482 CHECK(mat(2, 0) == doctest::Approx(3.0));
483 CHECK(mat(3, 0) == doctest::Approx(4.0));
484 CHECK(mat(4, 0) == doctest::Approx(5.0));
485 }
486
487 // Modify dof1, verify dof2 is unaffected (deep copy of raw data).
488 dof1.setConstant(-999.0);
489
490 for (DNDS::index i = 0; i < dof2.father->Size(); i++)
491 {
492 auto mat = dof2[i];
493 CHECK(mat(0, 0) == doctest::Approx(1.0));
494 CHECK(mat(4, 0) == doctest::Approx(5.0));
495 }
496}
497
498// ---------------------------------------------------------------------------
499TEST_CASE("ArrayDOF clone")
500{
501 MPIInfo mpi = worldMPI();
502 constexpr DNDS::index N = 30;
503
504 auto dof1 = makeDof<3, 1>(mpi, N);
505 Eigen::Matrix<real, 3, 1> v;
506 v << 7.0, 8.0, 9.0;
507 dof1.setConstant(v);
508
509 // clone creates a fully independent copy (new father/son allocations).
512
513 for (DNDS::index i = 0; i < dof2.father->Size(); i++)
514 {
515 auto mat = dof2[i];
516 CHECK(mat(0, 0) == doctest::Approx(7.0));
517 CHECK(mat(1, 0) == doctest::Approx(8.0));
518 CHECK(mat(2, 0) == doctest::Approx(9.0));
519 }
520
521 // Modify original, verify clone unchanged.
522 dof1.setConstant(0.0);
523 CHECK(dof2[0](0, 0) == doctest::Approx(7.0));
524}
525
526// ---------------------------------------------------------------------------
527TEST_CASE("ArrayDOF scalar array multiply")
528{
529 MPIInfo mpi = worldMPI();
530 constexpr DNDS::index N = 50;
531
532 auto dof = makeDof<3, 1>(mpi, N);
533 Eigen::Matrix<real, 3, 1> v;
534 v << 2.0, 4.0, 6.0;
535 dof.setConstant(v);
536
537 // Build a scalar ArrayDof<1,1> with per-cell scaling factors.
538 auto scale = makeDof<1, 1>(mpi, N);
539 scale.setConstant(3.0);
540
541 // dof *= scale multiplies each cell's vector by the scalar.
542 dof *= scale;
543
544 for (DNDS::index i = 0; i < dof.father->Size(); i++)
545 {
546 auto mat = dof[i];
547 CHECK(mat(0, 0) == doctest::Approx(6.0));
548 CHECK(mat(1, 0) == doctest::Approx(12.0));
549 CHECK(mat(2, 0) == doctest::Approx(18.0));
550 }
551}
552
553// ---------------------------------------------------------------------------
554TEST_CASE("ArrayDOF norm2 zero array")
555{
556 MPIInfo mpi = worldMPI();
557 constexpr DNDS::index N = 100;
558
559 auto dof = makeDof<5, 1>(mpi, N);
560 dof.setConstant(0.0);
561
562 CHECK(dof.norm2() == doctest::Approx(0.0));
563}
564
565// ---------------------------------------------------------------------------
566TEST_CASE("ArrayDOF dot self equals norm2 squared")
567{
568 MPIInfo mpi = worldMPI();
569 constexpr DNDS::index N = 100;
570
571 auto dof = makeDof<5, 1>(mpi, N);
572 Eigen::Matrix<real, 5, 1> v;
573 v << 1.0, -2.0, 3.0, -4.0, 5.0;
574 dof.setConstant(v);
575
576 real n2 = dof.norm2();
577 real d = dof.dot(dof);
578
579 CHECK(d == doctest::Approx(n2 * n2));
580}
581
582// ---------------------------------------------------------------------------
583// Parametric tests over nVars dimension
584// ---------------------------------------------------------------------------
585
586template <int M>
587struct DofTag
588{
589 static constexpr int m = M;
590};
591
596
597TEST_CASE_TEMPLATE("ArrayDOF parametric over nVars", T,
599{
600 MPIInfo mpi = worldMPI();
601 constexpr DNDS::index N = 64;
602 constexpr int M = T::m;
603
604 // For DynamicSize, rows must be provided at runtime. Pick 4 as the
605 // runtime row count so it differs from every fixed tag.
606 constexpr DNDS::rowsize rtRows = 4;
607 const int effectiveRows = (M == DNDS::DynamicSize) ? rtRows : M;
608
609 // Helper lambda to build the dof with the right overload.
610 auto buildDof = [&]()
611 {
612 if constexpr (M == DNDS::DynamicSize)
613 return makeDof<DNDS::DynamicSize, 1>(mpi, N, rtRows, 1);
614 else
615 return makeDof<M, 1>(mpi, N);
616 };
617
618 SUBCASE("setConstant scalar")
619 {
620 auto dof = buildDof();
621 dof.setConstant(3.0);
622
623 for (DNDS::index i = 0; i < dof.father->Size(); i++)
624 {
625 auto mat = dof[i];
626 CHECK(mat.rows() == effectiveRows);
627 for (int r = 0; r < mat.rows(); r++)
628 CHECK(mat(r, 0) == doctest::Approx(3.0));
629 }
630 }
631
632 SUBCASE("+= scalar")
633 {
634 auto dof = buildDof();
635 dof.setConstant(1.0);
636 dof += 4.0;
637
638 for (DNDS::index i = 0; i < dof.father->Size(); i++)
639 {
640 auto mat = dof[i];
641 for (int r = 0; r < mat.rows(); r++)
642 CHECK(mat(r, 0) == doctest::Approx(5.0));
643 }
644 }
645
646 SUBCASE("norm2")
647 {
648 auto dof = buildDof();
649 dof.setConstant(1.0);
650
651 real n2 = dof.norm2();
652 // Each cell contributes effectiveRows * 1^2.
653 real expected = std::sqrt(static_cast<real>(effectiveRows) * N * mpi.size);
654 CHECK(n2 == doctest::Approx(expected));
655 }
656
657 SUBCASE("dot")
658 {
659 auto dof1 = buildDof();
660 auto dof2 = buildDof();
661 dof1.setConstant(2.0);
662 dof2.setConstant(3.0);
663
664 real d = dof1.dot(dof2);
665 // Each cell: effectiveRows * (2*3) = effectiveRows * 6.
666 real expected = static_cast<real>(effectiveRows) * 6.0 * N * mpi.size;
667 CHECK(d == doctest::Approx(expected));
668 }
669
670 SUBCASE("clone")
671 {
672 auto dof1 = buildDof();
673 dof1.setConstant(7.0);
674
676 dof2.clone(dof1);
677
678 for (DNDS::index i = 0; i < dof2.father->Size(); i++)
679 {
680 auto mat = dof2[i];
681 CHECK(mat.rows() == effectiveRows);
682 for (int r = 0; r < mat.rows(); r++)
683 CHECK(mat(r, 0) == doctest::Approx(7.0));
684 }
685
686 // Modify original, verify clone unchanged.
687 dof1.setConstant(0.0);
688 CHECK(dof2[0](0, 0) == doctest::Approx(7.0));
689 }
690}
Degree-of-freedom array with vector-space operations (MPI-collective).
Primary solver state container: an ArrayEigenMatrix pair with MPI-collective vector-space operations.
Definition ArrayDOF.hpp:172
real norm2()
Global L2 norm (MPI-collective). sqrt(sum_i sum_j x_ij^2).
Definition ArrayDOF.hpp:301
t_element_mat componentWiseNorm1()
Per-component global L1 norm, returned as an n_m x n_n matrix (collective).
Definition ArrayDOF.hpp:331
real dot(const t_self &R)
Global inner product: sum_i sum_j x_ij * R_ij (collective).
Definition ArrayDOF.hpp:343
real max()
Global maximum across all entries (collective).
Definition ArrayDOF.hpp:319
void clone(const t_self &R)
Deep copy from another ArrayDof. Delegates to the base-class clone.
Definition ArrayDOF.hpp:211
real min()
Global minimum across all entries (collective).
Definition ArrayDOF.hpp:313
void setConstant(real R)
Set every entry of every (father+son) row to the scalar R.
Definition ArrayDOF.hpp:219
real sum()
Global sum of all entries (collective).
Definition ArrayDOF.hpp:325
int main()
Definition dummy.cpp:3
the host side operators are provided as implemented
int32_t rowsize
Row-width / per-row element-count type (signed 32-bit).
Definition Defines.hpp:109
DNDS_CONSTANT const rowsize DynamicSize
Template parameter flag: "row width is set at runtime but uniform".
Definition Defines.hpp:277
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:107
double real
Canonical floating-point scalar used throughout DNDSR (double precision).
Definition Defines.hpp:105
int MPI_int
MPI counterpart type for MPI_int (= C int). Used for counts and ranks in MPI calls.
Definition MPI.hpp:43
DNDS_DEVICE_CALLABLE index Size() const
Combined father + son row count.
Definition ArrayPair.hpp:33
void TransAttach()
Bind the transformer to the current father / son pointers.
ssp< TArray > father
Owned-side array (must be resized before ghost setup).
void InitPair(const std::string &name, Args &&...args)
Allocate both father and son arrays, forwarding all args to TArray constructor.
ssp< TArray > son
Ghost-side array (sized automatically by createMPITypes / BorrowAndPull).
Lightweight bundle of an MPI communicator and the calling rank's coordinates.
Definition MPI.hpp:215
static constexpr int m
CHECK(dof2[0](0, 0)==doctest::Approx(7.0))
Eigen::Matrix< real, 5, 1 > v
constexpr DNDS::index N
TYPE_TO_STRING(DofTag< 1 >)
TEST_CASE("ArrayDOF operator+= scalar and array")
auto dof2
auto dof1
TEST_CASE_TEMPLATE("ArrayDOF parametric over nVars", T, DofTag< 1 >, DofTag< 3 >, DofTag< 5 >, DofTag< DNDS::DynamicSize >)
tVec r(NCells)
real expected
auto res
Definition test_ODE.cpp:196