FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
saddle_point_matrix.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
9#include <kernel/lafem/tuple_vector.hpp>
10#include <kernel/lafem/dense_vector.hpp>
11#include <kernel/lafem/container.hpp>
12
13
14// includes, system
15#include <type_traits>
16#include <fstream>
17
18namespace FEAT
19{
20 namespace LAFEM
21 {
29 template<
30 typename MatrixA_,
31 typename MatrixB_,
32 typename MatrixD_,
33 int i_,
34 int j_>
36
61 template<
62 typename MatrixA_,
63 typename MatrixB_ = MatrixA_,
64 typename MatrixD_ = MatrixB_>
66 {
67 public:
69 typedef MatrixA_ MatrixTypeA;
71 typedef MatrixB_ MatrixTypeB;
73 typedef MatrixD_ MatrixTypeD;
74
75 // ensure that all matrices have the same and data-types
76 static_assert(std::is_same<typename MatrixA_::DataType, typename MatrixB_::DataType>::value,
77 "A and B have different data-types");
78 static_assert(std::is_same<typename MatrixA_::DataType, typename MatrixD_::DataType>::value,
79 "A and D have different data-types");
80
81 // ensure that the compatible vector types are the same
82 static_assert(std::is_same<typename MatrixA_::VectorTypeL, typename MatrixB_::VectorTypeL>::value,
83 "A and B have different compatible L-vectors");
84 static_assert(std::is_same<typename MatrixA_::VectorTypeR, typename MatrixD_::VectorTypeR>::value,
85 "A and D have different compatible R-vectors");
86
88 typedef typename MatrixTypeA::DataType DataType;
90 typedef typename MatrixTypeA::IndexType IndexType;
91
97 template <typename DT2_ = DataType, typename IT2_ = IndexType>
99 typename MatrixB_::template ContainerType<DT2_, IT2_>,
100 typename MatrixD_::template ContainerType<DT2_, IT2_> >;
101
103 template <typename DataType2_, typename IndexType2_>
105
107 static constexpr int num_row_blocks = 2;
109 static constexpr int num_col_blocks = 2;
110
111 protected:
118
119 public:
122 {
123 }
124
132 MatrixTypeA&& matrix_a,
133 MatrixTypeB&& matrix_b,
134 MatrixTypeD&& matrix_d) :
135 _matrix_a(std::move(matrix_a)),
136 _matrix_b(std::move(matrix_b)),
137 _matrix_d(std::move(matrix_d))
138 {
139 XASSERT(_matrix_a.rows() == _matrix_b.rows());
140 XASSERT(_matrix_a.columns() == _matrix_d.columns());
141 }
142
145 _matrix_a(std::move(other._matrix_a)),
146 _matrix_b(std::move(other._matrix_b)),
147 _matrix_d(std::move(other._matrix_d))
148 {
149 }
150
159 explicit SaddlePointMatrix(FileMode mode, const String& filename)
160 {
161 read_from(mode, filename);
162 }
163
170 void read_from(FileMode mode, const String& filename)
171 {
172 String directory;
173 auto found = filename.rfind("/");
174 if (found != std::string::npos)
175 {
176 directory = filename.substr(0, found + 1);
177 }
178
179 std::ifstream file(filename.c_str(), std::ifstream::in);
180 if (! file.is_open())
181 XABORTM("Unable to open Matrix file " + filename);
182
183 String line;
184 std::getline(file, line);
185 if (line.find("%%MatrixMarket saddlepointmatrix coordinate real general") == String::npos)
186 XABORTM("Input-file is not a complatible file");
187
188 do {
189 if (file.eof())
190 XABORTM("Wrong Input-file");
191 std::getline(file, line);
192 line.trim_me();
193 } while (line.find("%%") == 0 || line == "");
194
195 MatrixA_ tmp_a(mode, directory + line);
196 _matrix_a = std::move(tmp_a);
197
198 std::getline(file, line);
199 line.trim_me();
200 MatrixB_ tmp_b(mode, directory + line);
201 _matrix_b = std::move(tmp_b);
202
203 std::getline(file, line);
204 line.trim_me();
205 MatrixD_ tmp_d(mode, directory + line);
206 _matrix_d = std::move(tmp_d);
207
208 file.close();
209 }
210
213 {
214 if(this == &other)
215 return *this;
216 _matrix_a = std::move(other._matrix_a);
217 _matrix_b = std::move(other._matrix_b);
218 _matrix_d = std::move(other._matrix_d);
219 return *this;
220 }
221
224 {
225 }
226
233 void write_out(FileMode mode, String filename) const
234 {
235 std::ofstream file(filename.c_str(), std::ofstream::out);
236 if (! file.is_open())
237 XABORTM("Unable to open Matrix file " + filename);
238
239 String suffix, directory;
240 auto found = filename.rfind(".");
241 if (found != std::string::npos)
242 {
243 suffix = filename.substr(found);
244 filename.erase(found);
245 }
246 found = filename.rfind("/");
247 if (found != std::string::npos)
248 {
249 directory = filename.substr(0, found + 1);
250 filename.erase(0, found + 1);
251 }
252
253 file << "%%MatrixMarket saddlepointmatrix coordinate real general\n";
254 file << filename << "_a" << suffix << "\n";
255 file << filename << "_b" << suffix << "\n";
256 file << filename << "_d" << suffix << "\n";
257
258 file.close();
259
260 _matrix_a.write_out(mode, directory + filename + "_a" + suffix);
261 _matrix_b.write_out(mode, directory + filename + "_b" + suffix);
262 _matrix_d.write_out(mode, directory + filename + "_d" + suffix);
263 }
264
269 {
270 return SaddlePointMatrix(_matrix_a.clone(mode), _matrix_b.clone(mode), _matrix_d.clone(mode));
271 }
272
274 std::size_t bytes() const
275 {
276 return _matrix_a.bytes() + _matrix_b.bytes() + _matrix_d.bytes();
277 }
278
281 {
282 return _matrix_a;
283 }
284
286 const MatrixTypeA& block_a() const
287 {
288 return _matrix_a;
289 }
290
293 {
294 return _matrix_b;
295 }
296
298 const MatrixTypeB& block_b() const
299 {
300 return _matrix_b;
301 }
302
305 {
306 return _matrix_d;
307 }
308
310 const MatrixTypeD& block_d() const
311 {
312 return _matrix_d;
313 }
314
327 template<int i_, int j_>
329 {
330 static_assert((0 <= i_) && (0 <= j_), "invalid sub-matrix index");
331 static_assert((i_ <= 1) && (j_ <= 1), "invalid sub-matrix index");
332 static_assert((i_ < 1) || (j_ < 1), "sub-matrix block (1,1) does not exist in SaddlePointMatrix");
334 }
335
337 template<int i_, int j_>
339 {
340 static_assert((0 <= i_) && (0 <= j_), "invalid sub-matrix index");
341 static_assert((i_ <= 1) && (j_ <= 1), "invalid sub-matrix index");
342 static_assert((i_ < 1) || (j_ < 1), "sub-matrix block (1,1) does not exist in SaddlePointMatrix");
344 }
345
352 template <Perspective perspective_ = Perspective::native>
353 Index rows() const
354 {
355 return _matrix_a.template rows<perspective_>() + _matrix_d.template rows<perspective_>();
356 }
357
364 template <Perspective perspective_ = Perspective::native>
366 {
367 return _matrix_a.template columns<perspective_>() + _matrix_b.template columns<perspective_>();
368 }
369
376 template <Perspective perspective_ = Perspective::native>
378 {
379 return _matrix_a.template used_elements<perspective_>() + _matrix_b.template used_elements<perspective_>() + _matrix_d.template used_elements<perspective_>();
380 }
381
383 static String name()
384 {
385 return String("SaddePointMatrix<") + MatrixTypeA::name() + "," +
386 MatrixTypeB::name() + "," +
387 MatrixTypeD::name() + ">";
388 }
389
390 template <Perspective perspective_ = Perspective::native>
391 Index size() const
392 {
393 return rows<perspective_>() * columns<perspective_>();
394 }
395
403 {
404 block_a().format(value);
405 block_b().format(value);
406 block_d().format(value);
407 }
408
412 void clear()
413 {
414 block_a().clear();
415 block_b().clear();
416 block_d().clear();
417 }
418
420 void extract_diag(VectorTypeL& diag) const
421 {
422 _matrix_a.extract_diag(diag.first());
423 diag.rest().format();
424 }
425
426 void lump_rows(VectorTypeL& lump, bool /*sync*/ = true) const
427 {
428 _matrix_a.lump_rows(lump.first());
429 lump.rest().format();
430 }
431
444 void apply(VectorTypeL& r, const VectorTypeR& x) const
445 {
446 block_a().apply(r.template at<0>(), x.template at<0>());
447 block_b().apply(r.template at<0>(), x.template at<1>(), r.template at<0>(), DataType(1));
448 block_d().apply(r.template at<1>(), x.template at<0>());
449 }
450
452 {
453 XASSERTM(r.size() == this->rows(), "Vector size of r does not match!");
454 XASSERTM(x.size() == this->columns(), "Vector size of x does not match!");
455
458
461
462 block_a().apply(r_first, x_first);
463 block_b().apply(r_first, x_rest, r_first, DataType(1));
464 block_d().apply(r_rest, x_first);
465 }
466
479 void apply_transposed(VectorTypeR& r, const VectorTypeL& x) const
480 {
481 block_a().apply_transposed(r.template at<0>(), x.template at<0>());
482 block_d().apply_transposed(r.template at<0>(), x.template at<1>(), r.template at<0>(), DataType(1));
483 block_b().apply_transposed(r.template at<1>(), x.template at<0>());
484 }
485
487 {
488 XASSERTM(r.size() == this->columns(), "Vector size of r does not match!");
489 XASSERTM(x.size() == this->rows(), "Vector size of x does not match!");
490
493
496
497 block_a().apply_transposed(r_first, x_first);
498 block_d().apply_transposed(r_first, x_rest, r_first, DataType(1));
499 block_b().applytransposed(r_rest, x_first);
500 }
501
519 void apply(VectorTypeL& r, const VectorTypeR& x, const VectorTypeL& y, DataType alpha = DataType(1)) const
520 {
521 block_a().apply(r.template at<0>(), x.template at<0>(), y.template at<0>(), alpha);
522 block_b().apply(r.template at<0>(), x.template at<1>(), r.template at<0>(), alpha);
523 block_d().apply(r.template at<1>(), x.template at<0>(), y.template at<1>(), alpha);
524 }
525
527 const DenseVector<DataType, IndexType>& y, DataType alpha = DataType(1)) const
528 {
529 XASSERTM(r.size() == this->rows(), "Vector size of r does not match!");
530 XASSERTM(x.size() == this->columns(), "Vector size of x does not match!");
531 XASSERTM(y.size() == this->rows(), "Vector size of y does not match!");
532
535
538
541
542 block_a().apply(r_first, x_first, y_first, alpha);
543 block_b().apply(r_first, x_rest, r_first, alpha);
544 block_d().apply(r_rest, x_first, y_rest, alpha);
545 }
546
564 void apply_transposed(VectorTypeR& r, const VectorTypeL& x, const VectorTypeR& y, DataType alpha = DataType(1)) const
565 {
566 block_a().apply_transposed(r.template at<0>(), x.template at<0>(), y.template at<0>(), alpha);
567 block_d().apply_transposed(r.template at<0>(), x.template at<1>(), r.template at<0>(), alpha);
568 block_b().apply_transposed(r.template at<1>(), x.template at<0>(), y.template at<1>(), alpha);
569 }
570
572 const DenseVector<DataType, IndexType>& y, DataType alpha = DataType(1)) const
573 {
574 XASSERTM(r.size() == this->columns(), "Vector size of r does not match!");
575 XASSERTM(x.size() == this->rows(), "Vector size of x does not match!");
576 XASSERTM(y.size() == this->columns(), "Vector size of y does not match!");
577
580
583
586
587 block_a().apply_transposed(r_first, x_first, y_first, alpha);
588 block_d().apply_transposed(r_first, x_rest, r_first, alpha);
589 block_b().apply_transposed(r_rest, x_first, y_rest, alpha);
590 }
591
599 {
600 DataType max_rel_diff = Math::max(this->block_a().max_rel_diff(x.block_a()), this->block_b().max_rel_diff(x.block_b()));
602
603 return max_rel_diff;
604 }
605
614 bool same_layout(const SaddlePointMatrix& x) const
615 {
616 return (this->name() == x.name()) && (this->block_a().same_layout(x.block_a()))
617 && (this->block_b().same_layout(x.block_b())) && (this->block_d().same_layout(x.block_d()));
618 }
619
622 {
624 }
625
628 {
630 }
631
634 {
635 const Index arows(this->block_a().template rows<Perspective::pod>());
636
637 if (row < arows)
638 {
639 return this->block_a().get_length_of_line(row) + this->block_b().get_length_of_line(row);
640 }
641 else
642 {
643 return this->block_d().get_length_of_line(row - arows);
644 }
645 }
646
649 void set_line(const Index row, typename MatrixA_::DataType * const pval_set, typename MatrixA_::IndexType * const pcol_set,
650 const Index col_start, const Index stride = 1) const
651 {
652 const Index arows(this->block_a().template rows<Perspective::pod>());
653
654 if (row < arows)
655 {
656 const Index length_of_a(this->block_a().get_length_of_line(row));
657
658 this->block_a().set_line(row, pval_set, pcol_set, col_start, stride);
659 this->block_b().set_line(row, pval_set + stride * length_of_a, pcol_set + stride * length_of_a, col_start + this->block_a().template columns<Perspective::pod>(), stride);
660 }
661 else
662 {
663 this->block_d().set_line(row - arows, pval_set, pcol_set, col_start, stride);
664 }
665 }
666
667 void set_line_reverse(const Index row, const typename MatrixA_::DataType * const pval_set, const Index stride = 1)
668 {
669 const Index arows(this->block_a().template rows<Perspective::pod>());
670
671 if (row < arows)
672 {
673 const Index length_of_a(this->block_a().get_length_of_line(row));
674
675 this->block_a().set_line_reverse(row, pval_set, stride);
676 this->block_b().set_line_reverse(row, pval_set + stride * length_of_a, stride);
677 }
678 else
679 {
680 this->block_d().set_line_reverse(row - arows, pval_set, stride);
681 }
682 }
684
686 std::uint64_t get_checkpoint_size(SerialConfig& config)
687 {
688 return (3 * sizeof(std::uint64_t)) + this->block_a().get_checkpoint_size(config) + this->block_b().get_checkpoint_size(config) + this->block_d().get_checkpoint_size(config);
689 }
690
692 void restore_from_checkpoint_data(std::vector<char> & data)
693 {
694 std::uint64_t isize = *(std::uint64_t*) data.data(); //get size of checkpointed block a
695 std::vector<char>::iterator start = std::begin(data) + sizeof(std::uint64_t); //get iterator at the beginning of block a
696 std::vector<char>::iterator end = std::begin(data) + sizeof(std::uint64_t) + (int) isize; //get iterator at the beginning of block a
697 std::vector<char> buffer_a(start, end); //copy the data of block a to fresh vector
698 this->block_a().restore_from_checkpoint_data(buffer_a);
699
700 data.erase(std::begin(data), end);
701 isize = *(std::uint64_t*) data.data();
702 start = std::begin(data) + sizeof(std::uint64_t);
703 end = std::begin(data) + sizeof(std::uint64_t) + (int) isize;
704 std::vector<char> buffer_b(start, end);
705 this->block_b().restore_from_checkpoint_data(buffer_b);
706
707 data.erase(std::begin(data), end);
708 this->block_d().restore_from_checkpoint_data(data);
709 }
710
712 std::uint64_t set_checkpoint_data(std::vector<char>& data, SerialConfig& config)
713 {
714 std::size_t old_size = data.size();
715 data.insert(std::end(data), sizeof(std::uint64_t),0); //add placeholder
716 std::uint64_t ireal_size = this->block_a().set_checkpoint_data(data, config); //add data of block a to the overall checkpoint
717 std::uint64_t ret_size = ireal_size;
718 char* csize = reinterpret_cast<char*>(&ireal_size);
719 for(std::size_t i(0) ; i < sizeof(std::uint64_t) ; ++i) //overwrite the guessed datalength
720 {
721 data[old_size + i] = csize[i];
722 }
723
724 old_size = data.size();
725 data.insert(std::end(data), sizeof(std::uint64_t), 0); //add placeholder
726 ireal_size = this->block_b().set_checkpoint_data(data, config); //add data of block b to the overall checkpoint
727 ret_size += ireal_size;
728 csize = reinterpret_cast<char*>(&ireal_size);
729 for(std::size_t i(0) ; i < sizeof(std::uint64_t) ; ++i) //overwrite the guessed datalength
730 {
731 data[old_size + i] = csize[i];
732 }
733
734 return 2*sizeof(std::uint64_t) + ret_size + this->block_d().set_checkpoint_data(data, config); //add data of block d to the overall checkpoint
735 }
736
744 template <typename MatrixA2_, typename MatrixB2_, typename MatrixD2_>
746 {
747 this->block_a().convert(other.block_a());
748 this->block_b().convert(other.block_b());
749 this->block_d().convert(other.block_d());
750 }
751
752 template <typename MatrixA2_, typename MatrixB2_, typename MatrixD2_>
753 void convert_reverse(SaddlePointMatrix<MatrixA2_, MatrixB2_, MatrixD2_> & other) const
754 {
755 this->block_a().convert_reverse(other.block_a());
756 this->block_b().convert_reverse(other.block_b());
757 this->block_d().convert_reverse(other.block_d());
758 }
759 }; // class SaddlePointMatrix<...>
760
762 template<typename MatrixA_, typename MatrixB_, typename MatrixD_>
763 struct SaddlePointMatrixElement<MatrixA_, MatrixB_, MatrixD_, 0, 0>
764 {
765 typedef MatrixA_ Type;
766 static Type& get(SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& matrix)
767 {
768 return matrix.block_a();
769 }
770 static const Type& get(const SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& matrix)
771 {
772 return matrix.block_a();
773 }
774 };
775
776 template<typename MatrixA_, typename MatrixB_, typename MatrixD_>
777 struct SaddlePointMatrixElement<MatrixA_, MatrixB_, MatrixD_, 0, 1>
778 {
779 typedef MatrixB_ Type;
780 static Type& get(SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& matrix)
781 {
782 return matrix.block_b();
783 }
784 static const Type& get(const SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& matrix)
785 {
786 return matrix.block_b();
787 }
788 };
789
790 template<typename MatrixA_, typename MatrixB_, typename MatrixD_>
791 struct SaddlePointMatrixElement<MatrixA_, MatrixB_, MatrixD_, 1, 0>
792 {
793 typedef MatrixD_ Type;
794 static Type& get(SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& matrix)
795 {
796 return matrix.block_d();
797 }
798 static const Type& get(const SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& matrix)
799 {
800 return matrix.block_d();
801 }
802 };
804 } // namespace LAFEM
805} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
Index size() const
Returns the containers size.
Definition: container.hpp:1136
Dense data vector class template.
Saddle-Point matrix meta class template.
SaddlePointMatrix clone(LAFEM::CloneMode mode=LAFEM::CloneMode::Weak) const
Creates and returns a deep copy of this matrix.
void apply(VectorTypeL &r, const VectorTypeR &x, const VectorTypeL &y, DataType alpha=DataType(1)) const
Applies this matrix onto a vector.
MatrixD_ MatrixTypeD
type of sub-matrix D
const SaddlePointMatrixElement< MatrixA_, MatrixB_, MatrixD_, i_, j_ >::Type & at() const
Returns a sub-matrix block.
VectorTypeL create_vector_l() const
Returns a new compatible L-Vector.
MatrixB_ MatrixTypeB
type of sub-matrix B
static constexpr int num_row_blocks
number of row blocks (vertical size)
Index columns() const
Returns the total number of columns in this matrix.
bool same_layout(const SaddlePointMatrix &x) const
Checks if the structural layout of this matrix matches that of another matrix. This excludes comparis...
DataType max_rel_diff(const SaddlePointMatrix &x) const
Retrieve the maximum relative difference of this matrix and another one y.max_rel_diff(x) returns .
std::uint64_t set_checkpoint_data(std::vector< char > &data, SerialConfig &config)
void apply_transposed(VectorTypeR &r, const VectorTypeL &x) const
Applies this matrix onto a vector.
MatrixTypeA::DataType DataType
data type
void write_out(FileMode mode, String filename) const
Write out matrix to file.
MatrixTypeA & block_a()
Returns the sub-matrix block A.
SaddlePointMatrix(SaddlePointMatrix &&other)
move ctor
Index get_length_of_line(const Index row) const
Returns the number of NNZ-elements of the selected row.
VectorTypeR create_vector_r() const
Returns a new compatible R-Vector.
Index used_elements() const
Returns the total number of non-zeros in this matrix.
void apply(VectorTypeL &r, const VectorTypeR &x) const
Applies this matrix onto a vector.
const MatrixTypeB & block_b() const
Returns the sub-matrix block B.
MatrixTypeA::IndexType IndexType
index type
Index rows() const
Returns the total number of rows in this matrix.
MatrixA_ MatrixTypeA
type of sub-matrix A
static constexpr int num_col_blocks
number of column blocks (horizontal size)
void format(DataType value=DataType(0))
Reset all elements of the container to a given value or zero if missing.
std::uint64_t get_checkpoint_size(SerialConfig &config)
Calculate size.
TupleVector< typename MatrixTypeA::VectorTypeL, typename MatrixTypeD::VectorTypeL > VectorTypeL
Compatible L-vector type.
const MatrixTypeA & block_a() const
Returns the sub-matrix block A.
void clear()
Free all allocated arrays.
SaddlePointMatrix & operator=(SaddlePointMatrix &&other)
move-assign operator
static String name()
Returns a descriptive string for this container.
void convert(const SaddlePointMatrix< MatrixA2_, MatrixB2_, MatrixD2_ > &other)
Conversion method.
void extract_diag(VectorTypeL &diag) const
extract main diagonal vector from matrix
std::size_t bytes() const
Returns the total amount of bytes allocated.
void restore_from_checkpoint_data(std::vector< char > &data)
Extract object from checkpoint.
const MatrixTypeD & block_d() const
Returns the sub-matrix block D.
TupleVector< typename MatrixTypeA::VectorTypeR, typename MatrixTypeB::VectorTypeR > VectorTypeR
Compatible R-vector type.
MatrixTypeB & block_b()
Returns the sub-matrix block B.
SaddlePointMatrix(FileMode mode, const String &filename)
Constructor.
void read_from(FileMode mode, const String &filename)
Read in matrix from file.
SaddlePointMatrixElement< MatrixA_, MatrixB_, MatrixD_, i_, j_ >::Type & at()
Returns a sub-matrix block.
void apply_transposed(VectorTypeR &r, const VectorTypeL &x, const VectorTypeR &y, DataType alpha=DataType(1)) const
Applies this matrix onto a vector.
virtual ~SaddlePointMatrix()
virtual destructor
MatrixTypeD & block_d()
Returns the sub-matrix block D.
SaddlePointMatrix(MatrixTypeA &&matrix_a, MatrixTypeB &&matrix_b, MatrixTypeD &&matrix_d)
Sub-Matrix move constructor.
Config class for serialize parameter.
Definition: container.hpp:47
Variadic TupleVector class template.
void format(DataType value=DataType(0))
Reset all elements of the container to a given value or zero if missing.
String class implementation.
Definition: string.hpp:46
String & trim_me(const String &charset)
Trims this string.
Definition: string.hpp:358
T_ max(T_ a, T_ b)
Returns the maximum of two values.
Definition: math.hpp:137
Type
bitmask for zfp header
Definition: pack.hpp:81
FEAT namespace.
Definition: adjactor.hpp:12
@ value
specifies whether the space should supply basis function values
std::uint64_t Index
Index data type.
Saddle-Point matrix element helper class template.