GooseFEM 1.4.1.dev2+g78f16df
Loading...
Searching...
No Matches
MatrixPartitioned.h
Go to the documentation of this file.
1
11#ifndef GOOSEFEM_MATRIXPARTITIONED_H
12#define GOOSEFEM_MATRIXPARTITIONED_H
13
14#include "Matrix.h"
15#include "config.h"
16
17#include <Eigen/Eigen>
18#include <Eigen/Sparse>
19#include <Eigen/SparseCholesky>
20
21namespace GooseFEM {
22
23// forward declaration
24template <class>
25class MatrixPartitionedSolver;
26
34class MatrixPartitioned : public MatrixPartitionedBase<MatrixPartitioned> {
35private:
38
39protected:
40 Eigen::SparseMatrix<double> m_Auu;
41 Eigen::SparseMatrix<double> m_Aup;
42 Eigen::SparseMatrix<double> m_Apu;
43 Eigen::SparseMatrix<double> m_App;
44
45 std::vector<Eigen::Triplet<double>> m_Tuu;
46 std::vector<Eigen::Triplet<double>> m_Tup;
47 std::vector<Eigen::Triplet<double>> m_Tpu;
48 std::vector<Eigen::Triplet<double>> m_Tpp;
49
59
70
74 template <class>
76
77public:
78 MatrixPartitioned() = default;
79
91 )
92 {
93 m_conn = conn;
94 m_dofs = dofs;
95 m_iip = iip;
96 m_nelem = m_conn.shape(0);
97 m_nne = m_conn.shape(1);
98 m_nnode = m_dofs.shape(0);
99 m_ndim = m_dofs.shape(1);
100 m_ndof = xt::amax(m_dofs)() + 1;
101
103 GOOSEFEM_ASSERT(xt::amax(conn)() + 1 <= m_nnode);
104 GOOSEFEM_ASSERT(xt::amax(iip)() <= xt::amax(dofs)());
106
107 m_iiu = xt::setdiff1d(dofs, iip);
108 m_nnp = m_iip.size();
109 m_nnu = m_iiu.size();
110
112 m_part1d = Mesh::Reorder({m_iiu, m_iip}).apply(xt::eval(xt::arange<size_t>(m_ndof)));
113 m_Tuu.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim);
114 m_Tup.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim);
115 m_Tpu.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim);
116 m_Tpp.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim);
117 m_Auu.resize(m_nnu, m_nnu);
118 m_Aup.resize(m_nnu, m_nnp);
119 m_Apu.resize(m_nnp, m_nnu);
120 m_App.resize(m_nnp, m_nnp);
121 }
122
126 const Eigen::SparseMatrix<double>& data_uu() const
127 {
128 return m_Auu;
129 }
130
134 const Eigen::SparseMatrix<double>& data_up() const
135 {
136 return m_Aup;
137 }
138
142 const Eigen::SparseMatrix<double>& data_pu() const
143 {
144 return m_Apu;
145 }
146
150 const Eigen::SparseMatrix<double>& data_pp() const
151 {
152 return m_App;
153 }
154
155private:
156 template <class T>
157 void assemble_impl(const T& elemmat)
158 {
159 GOOSEFEM_ASSERT(xt::has_shape(elemmat, {m_nelem, m_nne * m_ndim, m_nne * m_ndim}));
160
161 m_Tuu.clear();
162 m_Tup.clear();
163 m_Tpu.clear();
164 m_Tpp.clear();
165
166 for (size_t e = 0; e < m_nelem; ++e) {
167 for (size_t m = 0; m < m_nne; ++m) {
168 for (size_t i = 0; i < m_ndim; ++i) {
169
170 size_t di = m_part(m_conn(e, m), i);
171
172 for (size_t n = 0; n < m_nne; ++n) {
173 for (size_t j = 0; j < m_ndim; ++j) {
174
175 size_t dj = m_part(m_conn(e, n), j);
176
177 if (di < m_nnu && dj < m_nnu) {
178 m_Tuu.push_back(Eigen::Triplet<double>(
179 di, dj, elemmat(e, m * m_ndim + i, n * m_ndim + j)
180 ));
181 }
182 else if (di < m_nnu) {
183 m_Tup.push_back(Eigen::Triplet<double>(
184 di, dj - m_nnu, elemmat(e, m * m_ndim + i, n * m_ndim + j)
185 ));
186 }
187 else if (dj < m_nnu) {
188 m_Tpu.push_back(Eigen::Triplet<double>(
189 di - m_nnu, dj, elemmat(e, m * m_ndim + i, n * m_ndim + j)
190 ));
191 }
192 else {
193 m_Tpp.push_back(Eigen::Triplet<double>(
194 di - m_nnu,
195 dj - m_nnu,
196 elemmat(e, m * m_ndim + i, n * m_ndim + j)
197 ));
198 }
199 }
200 }
201 }
202 }
203 }
204
205 m_Auu.setFromTriplets(m_Tuu.begin(), m_Tuu.end());
206 m_Aup.setFromTriplets(m_Tup.begin(), m_Tup.end());
207 m_Apu.setFromTriplets(m_Tpu.begin(), m_Tpu.end());
208 m_App.setFromTriplets(m_Tpp.begin(), m_Tpp.end());
209 m_changed = true;
210 }
211
212public:
220 void
224 {
225 GOOSEFEM_ASSERT(rows.size() == matrix.shape(0));
226 GOOSEFEM_ASSERT(cols.size() == matrix.shape(1));
227 GOOSEFEM_ASSERT(xt::amax(cols)() < m_ndof);
228 GOOSEFEM_ASSERT(xt::amax(rows)() < m_ndof);
229
230 std::vector<Eigen::Triplet<double>> Tuu;
231 std::vector<Eigen::Triplet<double>> Tup;
232 std::vector<Eigen::Triplet<double>> Tpu;
233 std::vector<Eigen::Triplet<double>> Tpp;
234
235 for (size_t i = 0; i < rows.size(); ++i) {
236 for (size_t j = 0; j < cols.size(); ++j) {
237 size_t di = m_part1d(rows(i));
238 size_t dj = m_part1d(cols(j));
239 double v = matrix(i, j);
240
241 if (di < m_nnu && dj < m_nnu) {
242 Tuu.push_back(Eigen::Triplet<double>(di, dj, v));
243 }
244 else if (di < m_nnu) {
245 Tup.push_back(Eigen::Triplet<double>(di, dj - m_nnu, v));
246 }
247 else if (dj < m_nnu) {
248 Tpu.push_back(Eigen::Triplet<double>(di - m_nnu, dj, v));
249 }
250 else {
251 Tpp.push_back(Eigen::Triplet<double>(di - m_nnu, dj - m_nnu, v));
252 }
253 }
254 }
255
256 m_Auu.setFromTriplets(Tuu.begin(), Tuu.end());
257 m_Aup.setFromTriplets(Tup.begin(), Tup.end());
258 m_Apu.setFromTriplets(Tpu.begin(), Tpu.end());
259 m_App.setFromTriplets(Tpp.begin(), Tpp.end());
260 m_changed = true;
261 }
262
270 void
274 {
275 GOOSEFEM_ASSERT(rows.size() == matrix.shape(0));
276 GOOSEFEM_ASSERT(cols.size() == matrix.shape(1));
277 GOOSEFEM_ASSERT(xt::amax(cols)() < m_ndof);
278 GOOSEFEM_ASSERT(xt::amax(rows)() < m_ndof);
279
280 std::vector<Eigen::Triplet<double>> Tuu;
281 std::vector<Eigen::Triplet<double>> Tup;
282 std::vector<Eigen::Triplet<double>> Tpu;
283 std::vector<Eigen::Triplet<double>> Tpp;
284
285 Eigen::SparseMatrix<double> Auu(m_nnu, m_nnu);
286 Eigen::SparseMatrix<double> Aup(m_nnu, m_nnp);
287 Eigen::SparseMatrix<double> Apu(m_nnp, m_nnu);
288 Eigen::SparseMatrix<double> App(m_nnp, m_nnp);
289
290 for (size_t i = 0; i < rows.size(); ++i) {
291 for (size_t j = 0; j < cols.size(); ++j) {
292 size_t di = m_part1d(rows(i));
293 size_t dj = m_part1d(cols(j));
294 double v = matrix(i, j);
295
296 if (di < m_nnu && dj < m_nnu) {
297 Tuu.push_back(Eigen::Triplet<double>(di, dj, v));
298 }
299 else if (di < m_nnu) {
300 Tup.push_back(Eigen::Triplet<double>(di, dj - m_nnu, v));
301 }
302 else if (dj < m_nnu) {
303 Tpu.push_back(Eigen::Triplet<double>(di - m_nnu, dj, v));
304 }
305 else {
306 Tpp.push_back(Eigen::Triplet<double>(di - m_nnu, dj - m_nnu, v));
307 }
308 }
309 }
310
311 Auu.setFromTriplets(Tuu.begin(), Tuu.end());
312 Aup.setFromTriplets(Tup.begin(), Tup.end());
313 Apu.setFromTriplets(Tpu.begin(), Tpu.end());
314 App.setFromTriplets(Tpp.begin(), Tpp.end());
315 m_Auu += Auu;
316 m_Aup += Aup;
317 m_Apu += Apu;
318 m_App += App;
319 m_changed = true;
320 }
321
322private:
323 template <class T>
324 void todense_impl(T& ret) const
325 {
326 ret.fill(0.0);
327
328 for (int k = 0; k < m_Auu.outerSize(); ++k) {
329 for (Eigen::SparseMatrix<double>::InnerIterator it(m_Auu, k); it; ++it) {
330 ret(m_iiu(it.row()), m_iiu(it.col())) = it.value();
331 }
332 }
333
334 for (int k = 0; k < m_Aup.outerSize(); ++k) {
335 for (Eigen::SparseMatrix<double>::InnerIterator it(m_Aup, k); it; ++it) {
336 ret(m_iiu(it.row()), m_iip(it.col())) = it.value();
337 }
338 }
339
340 for (int k = 0; k < m_Apu.outerSize(); ++k) {
341 for (Eigen::SparseMatrix<double>::InnerIterator it(m_Apu, k); it; ++it) {
342 ret(m_iip(it.row()), m_iiu(it.col())) = it.value();
343 }
344 }
345
346 for (int k = 0; k < m_App.outerSize(); ++k) {
347 for (Eigen::SparseMatrix<double>::InnerIterator it(m_App, k); it; ++it) {
348 ret(m_iip(it.row()), m_iip(it.col())) = it.value();
349 }
350 }
351 }
352
353 template <class T>
354 void dot_nodevec_impl(const T& x, T& b) const
355 {
356 GOOSEFEM_ASSERT(xt::has_shape(b, {m_nnode, m_ndim}));
357 GOOSEFEM_ASSERT(xt::has_shape(x, {m_nnode, m_ndim}));
358
359 Eigen::VectorXd X_u = this->AsDofs_u(x);
360 Eigen::VectorXd X_p = this->AsDofs_p(x);
361 Eigen::VectorXd B_u = m_Auu * X_u + m_Aup * X_p;
362 Eigen::VectorXd B_p = m_Apu * X_u + m_App * X_p;
363
364#pragma omp parallel for
365 for (size_t m = 0; m < m_nnode; ++m) {
366 for (size_t i = 0; i < m_ndim; ++i) {
367 if (m_part(m, i) < m_nnu) {
368 b(m, i) = B_u(m_part(m, i));
369 }
370 else {
371 b(m, i) = B_p(m_part(m, i) - m_nnu);
372 }
373 }
374 }
375 }
376
377 template <class T>
378 void dot_dofval_impl(const T& x, T& b) const
379 {
380 GOOSEFEM_ASSERT(b.size() == m_ndof);
381 GOOSEFEM_ASSERT(x.size() == m_ndof);
382
383 Eigen::VectorXd X_u = this->AsDofs_u(x);
384 Eigen::VectorXd X_p = this->AsDofs_p(x);
385
386 Eigen::VectorXd B_u = m_Auu * X_u + m_Aup * X_p;
387 Eigen::VectorXd B_p = m_Apu * X_u + m_App * X_p;
388
389#pragma omp parallel for
390 for (size_t d = 0; d < m_nnu; ++d) {
391 b(m_iiu(d)) = B_u(d);
392 }
393
394#pragma omp parallel for
395 for (size_t d = 0; d < m_nnp; ++d) {
396 b(m_iip(d)) = B_p(d);
397 }
398 }
399
400 template <class T>
401 void reaction_nodevec_impl(const T& x, T& b) const
402 {
403 GOOSEFEM_ASSERT(xt::has_shape(x, {m_nnode, m_ndim}));
404 GOOSEFEM_ASSERT(xt::has_shape(b, {m_nnode, m_ndim}));
405
406 Eigen::VectorXd X_u = this->AsDofs_u(x);
407 Eigen::VectorXd X_p = this->AsDofs_p(x);
408 Eigen::VectorXd B_p = m_Apu * X_u + m_App * X_p;
409
410#pragma omp parallel for
411 for (size_t m = 0; m < m_nnode; ++m) {
412 for (size_t i = 0; i < m_ndim; ++i) {
413 if (m_part(m, i) >= m_nnu) {
414 b(m, i) = B_p(m_part(m, i) - m_nnu);
415 }
416 }
417 }
418 }
419
420 template <class T>
421 void reaction_dofval_impl(const T& x, T& b) const
422 {
423 GOOSEFEM_ASSERT(x.size() == m_ndof);
424 GOOSEFEM_ASSERT(b.size() == m_ndof);
425
426 Eigen::VectorXd X_u = this->AsDofs_u(x);
427 Eigen::VectorXd X_p = this->AsDofs_p(x);
428 Eigen::VectorXd B_p = m_Apu * X_u + m_App * X_p;
429
430#pragma omp parallel for
431 for (size_t d = 0; d < m_nnp; ++d) {
432 b(m_iip(d)) = B_p(d);
433 }
434 }
435
436 void reaction_p_impl(
437 const array_type::tensor<double, 1>& x_u,
438 const array_type::tensor<double, 1>& x_p,
439 array_type::tensor<double, 1>& b_p
440 ) const
441 {
442 GOOSEFEM_ASSERT(x_u.size() == m_nnu);
443 GOOSEFEM_ASSERT(x_p.size() == m_nnp);
444 GOOSEFEM_ASSERT(b_p.size() == m_nnp);
445
446 Eigen::Map<Eigen::VectorXd>(b_p.data(), b_p.size()).noalias() =
447 m_Apu * Eigen::Map<const Eigen::VectorXd>(x_u.data(), x_u.size()) +
448 m_App * Eigen::Map<const Eigen::VectorXd>(x_p.data(), x_p.size());
449 }
450
451private:
452 // Convert arrays (Eigen version of VectorPartitioned, which contains public functions)
453 Eigen::VectorXd AsDofs_u(const array_type::tensor<double, 1>& dofval) const
454 {
455 GOOSEFEM_ASSERT(dofval.size() == m_ndof);
456
457 Eigen::VectorXd dofval_u(m_nnu, 1);
458
459#pragma omp parallel for
460 for (size_t d = 0; d < m_nnu; ++d) {
461 dofval_u(d) = dofval(m_iiu(d));
462 }
463
464 return dofval_u;
465 }
466
467 Eigen::VectorXd AsDofs_u(const array_type::tensor<double, 2>& nodevec) const
468 {
469 GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim}));
470
471 Eigen::VectorXd dofval_u = Eigen::VectorXd::Zero(m_nnu, 1);
472
473#pragma omp parallel for
474 for (size_t m = 0; m < m_nnode; ++m) {
475 for (size_t i = 0; i < m_ndim; ++i) {
476 if (m_part(m, i) < m_nnu) {
477 dofval_u(m_part(m, i)) = nodevec(m, i);
478 }
479 }
480 }
481
482 return dofval_u;
483 }
484
485 Eigen::VectorXd AsDofs_p(const array_type::tensor<double, 1>& dofval) const
486 {
487 GOOSEFEM_ASSERT(dofval.size() == m_ndof);
488
489 Eigen::VectorXd dofval_p(m_nnp, 1);
490
491#pragma omp parallel for
492 for (size_t d = 0; d < m_nnp; ++d) {
493 dofval_p(d) = dofval(m_iip(d));
494 }
495
496 return dofval_p;
497 }
498
499 Eigen::VectorXd AsDofs_p(const array_type::tensor<double, 2>& nodevec) const
500 {
501 GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim}));
502
503 Eigen::VectorXd dofval_p = Eigen::VectorXd::Zero(m_nnp, 1);
504
505#pragma omp parallel for
506 for (size_t m = 0; m < m_nnode; ++m) {
507 for (size_t i = 0; i < m_ndim; ++i) {
508 if (m_part(m, i) >= m_nnu) {
509 dofval_p(m_part(m, i) - m_nnu) = nodevec(m, i);
510 }
511 }
512 }
513
514 return dofval_p;
515 }
516};
517
525template <class Solver = Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>>>
527 : public MatrixSolverBase<MatrixPartitionedSolver<Solver>>,
528 public MatrixSolverPartitionedBase<MatrixPartitionedSolver<Solver>> {
529private:
532
533public:
534 MatrixPartitionedSolver() = default;
535
544 template <class M>
546 M& A,
549 )
550 {
551 GOOSEFEM_ASSERT(xt::has_shape(b_u, {A.nnu()}));
552 GOOSEFEM_ASSERT(xt::has_shape(x_p, {A.nnp()}));
553 array_type::tensor<double, 1> x_u = xt::empty_like(b_u);
554 this->solve_u_impl(A, b_u, x_p, x_u);
555 return x_u;
556 }
557
567 template <class M>
569 M& A,
573 )
574 {
575 GOOSEFEM_ASSERT(xt::has_shape(b_u, {A.nnu()}));
576 GOOSEFEM_ASSERT(xt::has_shape(x_p, {A.nnp()}));
577 GOOSEFEM_ASSERT(xt::has_shape(x_u, {A.nnu()}));
578 this->solve_u_impl(A, b_u, x_p, x_u);
579 }
580
581private:
582 template <class T>
583 void solve_nodevec_impl(MatrixPartitioned& A, const T& b, T& x)
584 {
585 this->factorize(A);
586 Eigen::VectorXd B_u = A.AsDofs_u(b);
587 Eigen::VectorXd X_p = A.AsDofs_p(x);
588 Eigen::VectorXd X_u = m_solver.solve(Eigen::VectorXd(B_u - A.m_Aup * X_p));
589
590#pragma omp parallel for
591 for (size_t m = 0; m < A.m_nnode; ++m) {
592 for (size_t i = 0; i < A.m_ndim; ++i) {
593 if (A.m_part(m, i) < A.m_nnu) {
594 x(m, i) = X_u(A.m_part(m, i));
595 }
596 }
597 }
598 }
599
600 template <class T>
601 void solve_dofval_impl(MatrixPartitioned& A, const T& b, T& x)
602 {
603 this->factorize(A);
604 Eigen::VectorXd B_u = A.AsDofs_u(b);
605 Eigen::VectorXd X_p = A.AsDofs_p(x);
606 Eigen::VectorXd X_u = m_solver.solve(Eigen::VectorXd(B_u - A.m_Aup * X_p));
607
608#pragma omp parallel for
609 for (size_t d = 0; d < A.m_nnu; ++d) {
610 x(A.m_iiu(d)) = X_u(d);
611 }
612 }
613
614 template <class T>
615 void solve_u_impl(MatrixPartitioned& A, const T& b_u, const T& x_p, T& x_u)
616 {
617 this->factorize(A);
618
619 Eigen::Map<Eigen::VectorXd>(x_u.data(), x_u.size()).noalias() =
620 m_solver.solve(Eigen::VectorXd(
621 Eigen::Map<const Eigen::VectorXd>(b_u.data(), b_u.size()) -
622 A.m_Aup * Eigen::Map<const Eigen::VectorXd>(x_p.data(), x_p.size())
623 ));
624 }
625
626private:
627 Solver m_solver;
628 bool m_factor = true;
629
633 void factorize(MatrixPartitioned& A)
634 {
635 if (!A.m_changed && !m_factor) {
636 return;
637 }
638 m_solver.compute(A.m_Auu);
639 m_factor = false;
640 A.m_changed = false;
641 }
642};
643
644} // namespace GooseFEM
645
646#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
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
array_type::tensor< size_t, 2 > m_conn
Connectivity [nelem, nne].
Definition Matrix.h:200
size_t m_nelem
See nelem().
Definition Matrix.h:203
size_t m_nne
See nne().
Definition Matrix.h:204
bool m_changed
Signal changes to data.
Definition Matrix.h:209
size_t m_nnode
See nnode().
Definition Matrix.h:205
size_t m_ndim
See ndim().
Definition Matrix.h:206
size_t m_ndof
See ndof().
Definition Matrix.h:207
CRTP base class for a partitioned matrix.
Definition Matrix.h:416
array_type::tensor< size_t, 1 > m_iiu
See iiu()
Definition Matrix.h:418
array_type::tensor< size_t, 1 > m_iip
See iip()
Definition Matrix.h:419
const array_type::tensor< size_t, 1 > & iip() const
Prescribed DOFs.
Definition Matrix.h:473
Solve for A of the MatrixPartitioned() class.
array_type::tensor< double, 1 > Solve_u(M &A, const array_type::tensor< double, 1 > &b_u, const array_type::tensor< double, 1 > &x_p)
Solve .
void solve_u(M &A, const array_type::tensor< double, 1 > &b_u, const array_type::tensor< double, 1 > &x_p, array_type::tensor< double, 1 > &x_u)
Same as Solve .
Sparse matrix partitioned in an unknown and a prescribed part.
std::vector< Eigen::Triplet< double > > m_Tuu
Matrix entries.
const Eigen::SparseMatrix< double > & data_uu() const
Pointer to data.
const Eigen::SparseMatrix< double > & data_pu() const
Pointer to data.
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.
const Eigen::SparseMatrix< double > & data_up() const
Pointer to data.
array_type::tensor< size_t, 1 > m_part1d
Map real DOF to DOF in partitioned system.
Eigen::SparseMatrix< double > m_App
The matrix.
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.
Eigen::SparseMatrix< double > m_Aup
The matrix.
std::vector< Eigen::Triplet< double > > m_Tup
Matrix entries.
array_type::tensor< size_t, 2 > m_part
Renumbered DOFs per node, such that:
Eigen::SparseMatrix< double > m_Auu
The matrix.
std::vector< Eigen::Triplet< double > > m_Tpu
Matrix entries.
const Eigen::SparseMatrix< double > & data_pp() const
Pointer to data.
Eigen::SparseMatrix< double > m_Apu
The matrix.
MatrixPartitioned(const array_type::tensor< size_t, 2 > &conn, const array_type::tensor< size_t, 2 > &dofs, const array_type::tensor< size_t, 1 > &iip)
Constructor.
std::vector< Eigen::Triplet< double > > m_Tpp
Matrix entries.
CRTP base class for a solver class.
Definition Matrix.h:26
CRTP base class for a extra functions for a partitioned solver class.
Definition Matrix.h:136
Reorder to lowest possible index, in specific order.
Definition Mesh.h:2384
Basic configuration:
#define GOOSEFEM_ASSERT(expr)
All assertions are implementation as::
Definition config.h:97
xt::xtensor< T, N > tensor
Fixed (static) rank array.
Definition config.h:177
Toolbox to perform finite element computations.
Definition Allocate.h:14
bool is_unique(const T &arg)
Returns true is a list is unique (has not duplicate items).
Definition assertions.h:20
auto AsTensor(const T &arg, const S &shape)
"Broadcast" a scalar stored in an array (e.g.
Definition Allocate.h:167