FrictionQPotFEM 0.23.3
Loading...
Searching...
No Matches
Matrix.h
Go to the documentation of this file.
1
7#ifndef GOOSEFEM_MATRIX_H
8#define GOOSEFEM_MATRIX_H
9
10#include "config.h"
11
12#include <Eigen/Eigen>
13#include <Eigen/Sparse>
14#include <Eigen/SparseCholesky>
15
16namespace GooseFEM {
17
18// forward declaration
19template <class>
20class MatrixSolver;
21
25template <class D>
27public:
31 using derived_type = D;
32
33private:
34 auto derived_cast() -> derived_type&
35 {
36 return *static_cast<derived_type*>(this);
37 }
38
39 auto derived_cast() const -> const derived_type&
40 {
41 return *static_cast<const derived_type*>(this);
42 }
43
44public:
52 template <class M>
54 {
55 GOOSEFEM_ASSERT(xt::has_shape(b, A.shape_nodevec()));
56 GOOSEFEM_ASSERT(xt::has_shape(x, A.shape_nodevec()));
57 derived_cast().solve_nodevec_impl(A, b, x);
58 }
59
67 template <class M>
69 {
70 GOOSEFEM_ASSERT(xt::has_shape(b, A.shape_dofval()));
71 GOOSEFEM_ASSERT(xt::has_shape(x, A.shape_dofval()));
72 derived_cast().solve_dofval_impl(A, b, x);
73 }
74};
75
79template <class D>
81public:
85 using derived_type = D;
86
87private:
88 auto derived_cast() -> derived_type&
89 {
90 return *static_cast<derived_type*>(this);
91 }
92
93 auto derived_cast() const -> const derived_type&
94 {
95 return *static_cast<const derived_type*>(this);
96 }
97
98public:
106 template <class M>
108 {
109 GOOSEFEM_ASSERT(xt::has_shape(b, A.shape_nodevec()));
110 array_type::tensor<double, 2> x = xt::empty_like(b);
111 derived_cast().solve_nodevec_impl(A, b, x);
112 return x;
113 }
114
122 template <class M>
124 {
125 GOOSEFEM_ASSERT(xt::has_shape(b, A.shape_dofval()));
126 array_type::tensor<double, 1> x = xt::empty_like(b);
127 derived_cast().solve_dofval_impl(A, b, x);
128 return x;
129 }
130};
131
135template <class D>
137public:
141 using derived_type = D;
142
143private:
144 auto derived_cast() -> derived_type&
145 {
146 return *static_cast<derived_type*>(this);
147 }
148
149 auto derived_cast() const -> const derived_type&
150 {
151 return *static_cast<const derived_type*>(this);
152 }
153
154public:
163 template <class M>
164 array_type::tensor<double, 2>
166 {
167 GOOSEFEM_ASSERT(xt::has_shape(b, A.shape_nodevec()));
168 GOOSEFEM_ASSERT(xt::has_shape(x, A.shape_nodevec()));
170 derived_cast().solve_nodevec_impl(A, b, ret);
171 return ret;
172 }
173
182 template <class M>
185 {
186 GOOSEFEM_ASSERT(xt::has_shape(b, A.shape_dofval()));
187 GOOSEFEM_ASSERT(xt::has_shape(x, A.shape_dofval()));
189 derived_cast().solve_dofval_impl(A, b, ret);
190 return ret;
191 }
192};
193
197template <class D>
199protected:
202
203 size_t m_nelem;
204 size_t m_nne;
205 size_t m_nnode;
206 size_t m_ndim;
207 size_t m_ndof;
208
209 bool m_changed = true;
210
211public:
215 using derived_type = D;
216
217private:
218 auto derived_cast() -> derived_type&
219 {
220 return *static_cast<derived_type*>(this);
221 }
222
223 auto derived_cast() const -> const derived_type&
224 {
225 return *static_cast<const derived_type*>(this);
226 }
227
228public:
233 size_t nelem() const
234 {
235 return derived_cast().m_nelem;
236 }
237
242 size_t nne() const
243 {
244 return derived_cast().m_nne;
245 }
246
251 size_t nnode() const
252 {
253 return derived_cast().m_nnode;
254 }
255
260 size_t ndim() const
261 {
262 return derived_cast().m_ndim;
263 }
264
269 size_t ndof() const
270 {
271 return derived_cast().m_ndof;
272 }
273
279 {
280 return derived_cast().m_dofs;
281 }
282
288 {
289 return derived_cast().m_conn;
290 }
291
296 std::array<size_t, 1> shape_dofval() const
297 {
298 return std::array<size_t, 1>{derived_cast().m_ndof};
299 }
300
305 std::array<size_t, 2> shape_nodevec() const
306 {
307 return std::array<size_t, 2>{derived_cast().m_nnode, derived_cast().m_ndim};
308 }
309
314 std::array<size_t, 3> shape_elemmat() const
315 {
316 return std::array<size_t, 3>{
317 derived_cast().m_nelem,
318 derived_cast().m_nne * derived_cast().m_ndim,
319 derived_cast().m_nne * derived_cast().m_ndim};
320 }
321
326 template <class T>
327 void assemble(const T& elemmat)
328 {
329 GOOSEFEM_ASSERT(xt::has_shape(elemmat, this->shape_elemmat()));
330 derived_cast().assemble_impl(elemmat);
331 }
332
338 {
339 size_t ndof = derived_cast().m_ndof;
340 array_type::tensor<double, 2> ret = xt::empty<double>({ndof, ndof});
341 derived_cast().todense_impl(ret);
342 return ret;
343 }
344
349 template <class T>
350 void todense(T& ret) const
351 {
352 GOOSEFEM_ASSERT(xt::has_shape(ret, {derived_cast().m_ndof, derived_cast().m_ndof}));
353 derived_cast().todense_impl(ret);
354 }
355
363 {
364 GOOSEFEM_ASSERT(xt::has_shape(x, this->shape_nodevec()));
365 array_type::tensor<double, 2> b = xt::empty_like(x);
366 derived_cast().dot_nodevec_impl(x, b);
367 return b;
368 }
369
377 {
378 GOOSEFEM_ASSERT(xt::has_shape(x, this->shape_dofval()));
379 array_type::tensor<double, 1> b = xt::empty_like(x);
380 derived_cast().dot_dofval_impl(x, b);
381 return b;
382 }
383
391 {
392 GOOSEFEM_ASSERT(xt::has_shape(x, this->shape_nodevec()));
393 GOOSEFEM_ASSERT(xt::has_shape(b, this->shape_nodevec()));
394 derived_cast().dot_nodevec_impl(x, b);
395 }
396
404 {
405 GOOSEFEM_ASSERT(xt::has_shape(x, this->shape_dofval()));
406 GOOSEFEM_ASSERT(xt::has_shape(b, this->shape_dofval()));
407 derived_cast().dot_dofval_impl(x, b);
408 }
409};
410
414template <class D>
416protected:
419
420 size_t m_nnu;
421 size_t m_nnp;
422
423public:
427 using derived_type = D;
428
429private:
430 auto derived_cast() -> derived_type&
431 {
432 return *static_cast<derived_type*>(this);
433 }
434
435 auto derived_cast() const -> const derived_type&
436 {
437 return *static_cast<const derived_type*>(this);
438 }
439
440public:
445 size_t nnu() const
446 {
447 return derived_cast().m_nnu;
448 }
449
454 size_t nnp() const
455 {
456 return derived_cast().m_nnp;
457 }
458
464 {
465 return derived_cast().m_iiu;
466 }
467
473 {
474 return derived_cast().m_iip;
475 }
476
490 {
491 GOOSEFEM_ASSERT(xt::has_shape(x, this->shape_nodevec()));
492 GOOSEFEM_ASSERT(xt::has_shape(b, this->shape_nodevec()));
494 derived_cast().reaction_nodevec_impl(x, ret);
495 return ret;
496 }
497
508 {
509 GOOSEFEM_ASSERT(xt::has_shape(x, this->shape_dofval()));
510 GOOSEFEM_ASSERT(xt::has_shape(b, this->shape_dofval()));
512 derived_cast().reaction_dofval_impl(x, ret);
513 return ret;
514 }
515
524 {
525 GOOSEFEM_ASSERT(xt::has_shape(x, this->shape_nodevec()));
526 GOOSEFEM_ASSERT(xt::has_shape(b, this->shape_nodevec()));
527 derived_cast().reaction_nodevec_impl(x, b);
528 }
529
538 {
539 GOOSEFEM_ASSERT(xt::has_shape(x, this->shape_dofval()));
540 GOOSEFEM_ASSERT(xt::has_shape(b, this->shape_dofval()));
541 derived_cast().reaction_dofval_impl(x, b);
542 }
543
554 const array_type::tensor<double, 1>& x_p) const
555 {
556 array_type::tensor<double, 1> b_p = xt::empty<double>({m_nnp});
557 derived_cast().reaction_p_impl(x_u, x_p, b_p);
558 return b_p;
559 }
560
573 {
574 derived_cast().reaction_p_impl(x_u, x_p, b_p);
575 }
576};
577
581template <class D>
583protected:
586
587 size_t m_nni;
588 size_t m_nnd;
589
590public:
594 using derived_type = D;
595
596private:
597 auto derived_cast() -> derived_type&
598 {
599 return *static_cast<derived_type*>(this);
600 }
601
602 auto derived_cast() const -> const derived_type&
603 {
604 return *static_cast<const derived_type*>(this);
605 }
606
607public:
612 size_t nni() const
613 {
614 return derived_cast().m_nni;
615 }
616
621 size_t nnd() const
622 {
623 return derived_cast().m_nnd;
624 }
625
631 {
632 return derived_cast().m_iii;
633 }
634
640 {
641 return derived_cast().m_iid;
642 }
643};
644
650class Matrix : public MatrixBase<Matrix> {
651private:
652 friend MatrixBase<Matrix>;
653
654private:
655 bool m_changed = true;
656
657 Eigen::SparseMatrix<double> m_A;
658
659 std::vector<Eigen::Triplet<double>> m_T;
660
664 template <class>
665 friend class MatrixSolver;
666
667public:
668 Matrix() = default;
669
677 {
678 m_conn = conn;
679 m_dofs = dofs;
680 m_nelem = m_conn.shape(0);
681 m_nne = m_conn.shape(1);
682 m_nnode = m_dofs.shape(0);
683 m_ndim = m_dofs.shape(1);
684 m_ndof = xt::amax(m_dofs)() + 1;
685 m_T.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim);
686 m_A.resize(m_ndof, m_ndof);
687
688 GOOSEFEM_ASSERT(xt::amax(m_conn)() + 1 <= m_nnode);
690 }
691
695 const Eigen::SparseMatrix<double>& data() const
696 {
697 return m_A;
698 }
699
700private:
701 template <class T>
702 void assemble_impl(const T& elemmat)
703 {
704 m_T.clear();
705
706 for (size_t e = 0; e < m_nelem; ++e) {
707 for (size_t m = 0; m < m_nne; ++m) {
708 for (size_t i = 0; i < m_ndim; ++i) {
709 for (size_t n = 0; n < m_nne; ++n) {
710 for (size_t j = 0; j < m_ndim; ++j) {
711 m_T.push_back(Eigen::Triplet<double>(
712 m_dofs(m_conn(e, m), i),
713 m_dofs(m_conn(e, n), j),
714 elemmat(e, m * m_ndim + i, n * m_ndim + j)));
715 }
716 }
717 }
718 }
719 }
720
721 m_A.setFromTriplets(m_T.begin(), m_T.end());
722 m_changed = true;
723 }
724
725public:
733 void
736 const array_type::tensor<double, 2>& matrix)
737 {
738 GOOSEFEM_ASSERT(rows.size() == matrix.shape(0));
739 GOOSEFEM_ASSERT(cols.size() == matrix.shape(1));
740 GOOSEFEM_ASSERT(xt::amax(cols)() < m_ndof);
741 GOOSEFEM_ASSERT(xt::amax(rows)() < m_ndof);
742
743 std::vector<Eigen::Triplet<double>> T;
744
745 for (size_t i = 0; i < rows.size(); ++i) {
746 for (size_t j = 0; j < cols.size(); ++j) {
747 T.push_back(Eigen::Triplet<double>(rows(i), cols(j), matrix(i, j)));
748 }
749 }
750
751 m_A.setFromTriplets(T.begin(), T.end());
752 m_changed = true;
753 }
754
762 void
765 const array_type::tensor<double, 2>& matrix)
766 {
767 GOOSEFEM_ASSERT(rows.size() == matrix.shape(0));
768 GOOSEFEM_ASSERT(cols.size() == matrix.shape(1));
769 GOOSEFEM_ASSERT(xt::amax(cols)() < m_ndof);
770 GOOSEFEM_ASSERT(xt::amax(rows)() < m_ndof);
771
772 std::vector<Eigen::Triplet<double>> T;
773
774 Eigen::SparseMatrix<double> A(m_ndof, m_ndof);
775
776 for (size_t i = 0; i < rows.size(); ++i) {
777 for (size_t j = 0; j < cols.size(); ++j) {
778 T.push_back(Eigen::Triplet<double>(rows(i), cols(j), matrix(i, j)));
779 }
780 }
781
782 A.setFromTriplets(T.begin(), T.end());
783 m_A += A;
784 m_changed = true;
785 }
786
787private:
788 template <class T>
789 void todense_impl(T& ret) const
790 {
791 ret.fill(0.0);
792
793 for (int k = 0; k < m_A.outerSize(); ++k) {
794 for (Eigen::SparseMatrix<double>::InnerIterator it(m_A, k); it; ++it) {
795 ret(it.row(), it.col()) = it.value();
796 }
797 }
798 }
799
800 template <class T>
801 void dot_nodevec_impl(const T& x, T& b) const
802 {
803 this->Eigen_asNode_dofval_nodevec(m_A * this->Eigen_AsDofs_nodevec(x), b);
804 }
805
806 template <class T>
807 void dot_dofval_impl(const T& x, T& b) const
808 {
809 Eigen::Map<Eigen::VectorXd>(b.data(), b.size()).noalias() =
810 m_A * Eigen::Map<const Eigen::VectorXd>(x.data(), x.size());
811 }
812
813private:
820 template <class T>
821 Eigen::VectorXd Eigen_AsDofs_nodevec(const T& nodevec) const
822 {
823 GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim}));
824
825 Eigen::VectorXd dofval = Eigen::VectorXd::Zero(m_ndof, 1);
826
827#pragma omp parallel for
828 for (size_t m = 0; m < m_nnode; ++m) {
829 for (size_t i = 0; i < m_ndim; ++i) {
830 dofval(m_dofs(m, i)) = nodevec(m, i);
831 }
832 }
833
834 return dofval;
835 }
836
843 template <class T>
844 void Eigen_asNode_dofval_nodevec(const Eigen::VectorXd& dofval, T& nodevec) const
845 {
846 GOOSEFEM_ASSERT(static_cast<size_t>(dofval.size()) == m_ndof);
847 GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim}));
848
849#pragma omp parallel for
850 for (size_t m = 0; m < m_nnode; ++m) {
851 for (size_t i = 0; i < m_ndim; ++i) {
852 nodevec(m, i) = dofval(m_dofs(m, i));
853 }
854 }
855 }
856};
857
862template <class Solver = Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>>>
863class MatrixSolver : public MatrixSolverBase<MatrixSolver<Solver>>,
864 public MatrixSolverSingleBase<MatrixSolver<Solver>> {
865private:
868
869public:
870 MatrixSolver() = default;
871
872private:
873 template <class T>
874 void solve_nodevec_impl(Matrix& A, const T& b, T& x)
875 {
876 this->factorize(A);
877 Eigen::VectorXd X = m_solver.solve(A.Eigen_AsDofs_nodevec(b));
878 A.Eigen_asNode_dofval_nodevec(X, x);
879 }
880
881 template <class T>
882 void solve_dofval_impl(Matrix& A, const T& b, T& x)
883 {
884 this->factorize(A);
885 Eigen::Map<Eigen::VectorXd>(x.data(), x.size()).noalias() =
886 m_solver.solve(Eigen::Map<const Eigen::VectorXd>(b.data(), A.m_ndof));
887 }
888
889private:
890 Solver m_solver;
891 bool m_factor = true;
892
896 void factorize(Matrix& A)
897 {
898 if (!A.m_changed && !m_factor) {
899 return;
900 }
901 m_solver.compute(A.m_A);
902 m_factor = false;
903 A.m_changed = false;
904 }
905};
906
907} // namespace GooseFEM
908
909#endif
CRTP base class for a matrix.
Definition: Matrix.h:198
const array_type::tensor< size_t, 2 > & dofs() const
DOFs per node.
Definition: Matrix.h:278
size_t nne() const
Number of nodes per element.
Definition: Matrix.h:242
const array_type::tensor< size_t, 2 > & conn() const
Connectivity.
Definition: Matrix.h:287
array_type::tensor< size_t, 2 > m_dofs
DOF-numbers per node [nnode, ndim].
Definition: Matrix.h:201
size_t nnode() const
Number of nodes.
Definition: Matrix.h:251
array_type::tensor< size_t, 2 > m_conn
Connectivity [nelem, nne].
Definition: Matrix.h:200
std::array< size_t, 2 > shape_nodevec() const
Shape of "nodevec".
Definition: Matrix.h:305
size_t m_nelem
See nelem().
Definition: Matrix.h:203
array_type::tensor< double, 1 > Dot(const array_type::tensor< double, 1 > &x) const
Dot-product .
Definition: Matrix.h:376
void dot(const array_type::tensor< double, 1 > &x, array_type::tensor< double, 1 > &b) const
Dot-product .
Definition: Matrix.h:403
void assemble(const T &elemmat)
Assemble from "elemmat".
Definition: Matrix.h:327
std::array< size_t, 3 > shape_elemmat() const
Shape of "elemmat".
Definition: Matrix.h:314
array_type::tensor< double, 2 > Dot(const array_type::tensor< double, 2 > &x) const
Dot-product .
Definition: Matrix.h:362
size_t m_nne
See nne().
Definition: Matrix.h:204
size_t nelem() const
Number of elements.
Definition: Matrix.h:233
bool m_changed
Signal changes to data.
Definition: Matrix.h:209
size_t ndim() const
Number of dimensions.
Definition: Matrix.h:260
array_type::tensor< double, 2 > Todense() const
Copy as dense matrix.
Definition: Matrix.h:337
std::array< size_t, 1 > shape_dofval() const
Shape of "dofval".
Definition: Matrix.h:296
size_t m_nnode
See nnode().
Definition: Matrix.h:205
size_t m_ndim
See ndim().
Definition: Matrix.h:206
size_t ndof() const
Number of DOFs.
Definition: Matrix.h:269
void todense(T &ret) const
Copy to dense matrix.
Definition: Matrix.h:350
D derived_type
Underlying type.
Definition: Matrix.h:215
void dot(const array_type::tensor< double, 2 > &x, array_type::tensor< double, 2 > &b) const
Dot-product .
Definition: Matrix.h:390
size_t m_ndof
See ndof().
Definition: Matrix.h:207
CRTP base class for a partitioned matrix.
Definition: Matrix.h:415
const array_type::tensor< size_t, 1 > & iiu() const
Unknown DOFs.
Definition: Matrix.h:463
array_type::tensor< size_t, 1 > m_iiu
See iiu()
Definition: Matrix.h:417
void reaction(const array_type::tensor< double, 1 > &x, array_type::tensor< double, 1 > &b) const
Same as Reaction(const array_type::tensor<double, 1>&, const array_type::tensor<double,...
Definition: Matrix.h:537
size_t nnu() const
Number of unknown DOFs.
Definition: Matrix.h:445
size_t nnp() const
Number of prescribed DOFs.
Definition: Matrix.h:454
D derived_type
Underlying type.
Definition: Matrix.h:427
array_type::tensor< size_t, 1 > m_iip
See iip()
Definition: Matrix.h:418
const array_type::tensor< size_t, 1 > & iip() const
Prescribed DOFs.
Definition: Matrix.h:472
void reaction_p(const array_type::tensor< double, 1 > &x_u, const array_type::tensor< double, 1 > &x_p, array_type::tensor< double, 1 > &b_p) const
Same as Reaction_p(const array_type::tensor<double, 1>&, const array_type::tensor<double,...
Definition: Matrix.h:569
array_type::tensor< double, 1 > Reaction(const array_type::tensor< double, 1 > &x, const array_type::tensor< double, 1 > &b) const
Same as Reaction(const array_type::tensor<double, 2>&, const array_type::tensor<double,...
Definition: Matrix.h:507
void reaction(const array_type::tensor< double, 2 > &x, array_type::tensor< double, 2 > &b) const
Same as Reaction(const array_type::tensor<double, 2>&, const array_type::tensor<double,...
Definition: Matrix.h:523
array_type::tensor< double, 1 > Reaction_p(const array_type::tensor< double, 1 > &x_u, const array_type::tensor< double, 1 > &x_p) const
Same as Reaction(const array_type::tensor<double, 1>&, const array_type::tensor<double,...
Definition: Matrix.h:552
array_type::tensor< double, 2 > Reaction(const array_type::tensor< double, 2 > &x, const array_type::tensor< double, 2 > &b) const
Right-hand-size for corresponding to the prescribed DOFs:
Definition: Matrix.h:489
CRTP base class for a partitioned matrix with tying.
Definition: Matrix.h:582
array_type::tensor< size_t, 1 > m_iii
See iii()
Definition: Matrix.h:584
array_type::tensor< size_t, 1 > m_iid
See iid()
Definition: Matrix.h:585
size_t nnd() const
Number of dependent DOFs.
Definition: Matrix.h:621
size_t nni() const
Number of independent DOFs.
Definition: Matrix.h:612
D derived_type
Underlying type.
Definition: Matrix.h:594
const array_type::tensor< size_t, 1 > & iii() const
Independent DOFs.
Definition: Matrix.h:630
const array_type::tensor< size_t, 1 > & iid() const
Dependent DOFs.
Definition: Matrix.h:639
CRTP base class for a solver class.
Definition: Matrix.h:26
void solve(M &A, const array_type::tensor< double, 2 > &b, array_type::tensor< double, 2 > &x)
Solve .
Definition: Matrix.h:53
void solve(M &A, const array_type::tensor< double, 1 > &b, array_type::tensor< double, 1 > &x)
Solve .
Definition: Matrix.h:68
D derived_type
Underlying type.
Definition: Matrix.h:31
CRTP base class for a extra functions for a partitioned solver class.
Definition: Matrix.h:136
array_type::tensor< double, 1 > Solve(M &A, const array_type::tensor< double, 1 > &b, const array_type::tensor< double, 1 > &x)
Solve .
Definition: Matrix.h:184
D derived_type
Underlying type.
Definition: Matrix.h:141
array_type::tensor< double, 2 > Solve(M &A, const array_type::tensor< double, 2 > &b, const array_type::tensor< double, 2 > &x)
Solve .
Definition: Matrix.h:165
CRTP base class for a solver class.
Definition: Matrix.h:80
array_type::tensor< double, 2 > Solve(M &A, const array_type::tensor< double, 2 > &b)
Solve .
Definition: Matrix.h:107
array_type::tensor< double, 1 > Solve(M &A, const array_type::tensor< double, 1 > &b)
Solve .
Definition: Matrix.h:123
D derived_type
Underlying type.
Definition: Matrix.h:85
Solve , for A of the GooseFEM::Matrix() class.
Definition: Matrix.h:864
Sparse matrix.
Definition: Matrix.h:650
Matrix(const array_type::tensor< size_t, 2 > &conn, const array_type::tensor< size_t, 2 > &dofs)
Constructor.
Definition: Matrix.h:676
const Eigen::SparseMatrix< double > & data() const
Pointer to data.
Definition: Matrix.h:695
void add(const array_type::tensor< size_t, 1 > &rows, const array_type::tensor< size_t, 1 > &cols, const array_type::tensor< double, 2 > &matrix)
Add matrix.
Definition: Matrix.h:763
void set(const array_type::tensor< size_t, 1 > &rows, const array_type::tensor< size_t, 1 > &cols, const array_type::tensor< double, 2 > &matrix)
Overwrite matrix.
Definition: Matrix.h:734
#define GOOSEFEM_ASSERT(expr)
All assertions are implementation as::
Definition: config.h:96
xt::xtensor< T, N > tensor
Fixed (static) rank array.
Definition: config.h:176
Toolbox to perform finite element computations.
Definition: Allocate.h:14