deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
block_linear_operator.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2015 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_block_linear_operator_h
14#define dealii_block_linear_operator_h
15
16#include <deal.II/base/config.h>
17
19
21
22
24
25// Forward declarations:
26#ifndef DOXYGEN
27namespace internal
28{
29 namespace BlockLinearOperatorImplementation
30 {
31 template <typename PayloadBlockType =
33 class EmptyBlockPayload;
34 }
35} // namespace internal
36
37template <typename Number>
38class BlockVector;
39
40template <typename Range = BlockVector<double>,
41 typename Domain = Range,
42 typename BlockPayload =
43 internal::BlockLinearOperatorImplementation::EmptyBlockPayload<>>
45#endif
46
47template <typename Range = BlockVector<double>,
48 typename Domain = Range,
49 typename BlockPayload =
50 internal::BlockLinearOperatorImplementation::EmptyBlockPayload<>,
51 typename BlockMatrixType>
53block_operator(const BlockMatrixType &matrix);
54
55template <std::size_t m,
56 std::size_t n,
57 typename Range = BlockVector<double>,
58 typename Domain = Range,
59 typename BlockPayload =
63 const std::array<std::array<LinearOperator<typename Range::BlockType,
64 typename Domain::BlockType,
65 typename BlockPayload::BlockType>,
66 n>,
67 m> &);
68
69template <std::size_t m,
70 typename Range = BlockVector<double>,
71 typename Domain = Range,
72 typename BlockPayload =
76 const std::array<LinearOperator<typename Range::BlockType,
77 typename Domain::BlockType,
78 typename BlockPayload::BlockType>,
79 m> &);
80
81template <std::size_t m,
82 typename Range = BlockVector<double>,
83 typename Domain = Range,
84 typename BlockPayload =
88 const LinearOperator<typename Range::BlockType,
89 typename Domain::BlockType,
90 typename BlockPayload::BlockType> &op);
91
92
93
162template <typename Range, typename Domain, typename BlockPayload>
164 : public LinearOperator<Range, Domain, typename BlockPayload::BlockType>
165{
166public:
167 using BlockType = LinearOperator<typename Range::BlockType,
168 typename Domain::BlockType,
169 typename BlockPayload::BlockType>;
170
178 BlockLinearOperator(const BlockPayload &payload)
179 : LinearOperator<Range, Domain, typename BlockPayload::BlockType>(
180 typename BlockPayload::BlockType(payload, payload))
181 {
182 n_block_rows = []() -> unsigned int {
183 Assert(
184 false,
186 "Uninitialized BlockLinearOperator<Range, Domain>::n_block_rows called"));
187 return 0;
188 };
189
190 n_block_cols = []() -> unsigned int {
191 Assert(
192 false,
194 "Uninitialized BlockLinearOperator<Range, Domain>::n_block_cols called"));
195 return 0;
196 };
197
198 block = [](unsigned int, unsigned int) -> BlockType {
199 Assert(
200 false,
202 "Uninitialized BlockLinearOperator<Range, Domain>::block called"));
203 return BlockType();
204 };
205 }
206
212
218 template <typename Op>
220 {
221 *this = block_operator<Range, Domain, BlockPayload, Op>(op);
222 }
223
229 template <std::size_t m, std::size_t n>
230 BlockLinearOperator(const std::array<std::array<BlockType, n>, m> &ops)
231 {
232 *this = block_operator<m, n, Range, Domain, BlockPayload>(ops);
233 }
234
240 template <std::size_t m>
241 BlockLinearOperator(const std::array<BlockType, m> &ops)
242 {
243 *this = block_diagonal_operator<m, Range, Domain, BlockPayload>(ops);
244 }
245
251
256 template <typename Op>
258 operator=(const Op &op)
259 {
260 *this = block_operator<Range, Domain, BlockPayload, Op>(op);
261 return *this;
262 }
263
269 template <std::size_t m, std::size_t n>
271 operator=(const std::array<std::array<BlockType, n>, m> &ops)
272 {
273 *this = block_operator<m, n, Range, Domain, BlockPayload>(ops);
274 return *this;
275 }
276
282 template <std::size_t m>
284 operator=(const std::array<BlockType, m> &ops)
285 {
286 *this = block_diagonal_operator<m, Range, Domain, BlockPayload>(ops);
287 return *this;
288 }
289
294 std::function<unsigned int()> n_block_rows;
295
300 std::function<unsigned int()> n_block_cols;
301
307 std::function<BlockType(unsigned int, unsigned int)> block;
308};
309
310
311namespace internal
312{
313 namespace BlockLinearOperatorImplementation
314 {
315 // A helper function to apply a given vmult, or Tvmult to a vector with
316 // intermediate storage, similar to the corresponding helper
317 // function for LinearOperator. Here, two operators are used.
318 // The first one takes care of the first "column" and typically doesn't add.
319 // On the other hand, the second operator is normally an adding one.
320 template <typename Function1,
321 typename Function2,
322 typename Range,
323 typename Domain>
324 void
325 apply_with_intermediate_storage(const Function1 &first_op,
326 const Function2 &loop_op,
327 Range &v,
328 const Domain &u,
329 bool add)
330 {
331 GrowingVectorMemory<Range> vector_memory;
332
333 typename VectorMemory<Range>::Pointer tmp(vector_memory);
334 tmp->reinit(v, /*bool omit_zeroing_entries =*/true);
335
336 const unsigned int n = u.n_blocks();
337 const unsigned int m = v.n_blocks();
338
339 for (unsigned int i = 0; i < m; ++i)
340 {
341 first_op(*tmp, u, i, 0);
342 for (unsigned int j = 1; j < n; ++j)
343 loop_op(*tmp, u, i, j);
344 }
345
346 if (add)
347 v += *tmp;
348 else
349 v = *tmp;
350 }
351
352 // Populate the LinearOperator interfaces with the help of the
353 // BlockLinearOperator functions
354 template <typename Range, typename Domain, typename BlockPayload>
355 inline void
358 {
359 op.reinit_range_vector = [=](Range &v, bool omit_zeroing_entries) {
360 const unsigned int m = op.n_block_rows();
361
362 // Reinitialize the block vector to m blocks:
363 v.reinit(m);
364
365 // And reinitialize every individual block with reinit_range_vectors:
366 for (unsigned int i = 0; i < m; ++i)
367 op.block(i, 0).reinit_range_vector(v.block(i), omit_zeroing_entries);
368
369 v.collect_sizes();
370 };
371
372 op.reinit_domain_vector = [=](Domain &v, bool omit_zeroing_entries) {
373 const unsigned int n = op.n_block_cols();
374
375 // Reinitialize the block vector to n blocks:
376 v.reinit(n);
377
378 // And reinitialize every individual block with reinit_domain_vectors:
379 for (unsigned int i = 0; i < n; ++i)
380 op.block(0, i).reinit_domain_vector(v.block(i), omit_zeroing_entries);
381
382 v.collect_sizes();
383 };
384
385 op.vmult = [&op](Range &v, const Domain &u) {
386 const unsigned int m = op.n_block_rows();
387 const unsigned int n = op.n_block_cols();
388 Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
389 Assert(u.n_blocks() == n, ExcDimensionMismatch(u.n_blocks(), n));
390
391 if (PointerComparison::equal(&v, &u))
392 {
393 const auto first_op = [&op](Range &v,
394 const Domain &u,
395 const unsigned int i,
396 const unsigned int j) {
397 op.block(i, j).vmult(v.block(i), u.block(j));
398 };
399
400 const auto loop_op = [&op](Range &v,
401 const Domain &u,
402 const unsigned int i,
403 const unsigned int j) {
404 op.block(i, j).vmult_add(v.block(i), u.block(j));
405 };
406
407 apply_with_intermediate_storage(first_op, loop_op, v, u, false);
408 }
409 else
410 {
411 for (unsigned int i = 0; i < m; ++i)
412 {
413 op.block(i, 0).vmult(v.block(i), u.block(0));
414 for (unsigned int j = 1; j < n; ++j)
415 op.block(i, j).vmult_add(v.block(i), u.block(j));
416 }
417 }
418 };
419
420 op.vmult_add = [&op](Range &v, const Domain &u) {
421 const unsigned int m = op.n_block_rows();
422 const unsigned int n = op.n_block_cols();
423 Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
424 Assert(u.n_blocks() == n, ExcDimensionMismatch(u.n_blocks(), n));
425
426 if (PointerComparison::equal(&v, &u))
427 {
428 const auto first_op = [&op](Range &v,
429 const Domain &u,
430 const unsigned int i,
431 const unsigned int j) {
432 op.block(i, j).vmult(v.block(i), u.block(j));
433 };
434
435 const auto loop_op = [&op](Range &v,
436 const Domain &u,
437 const unsigned int i,
438 const unsigned int j) {
439 op.block(i, j).vmult_add(v.block(i), u.block(j));
440 };
441
442 apply_with_intermediate_storage(first_op, loop_op, v, u, true);
443 }
444 else
445 {
446 for (unsigned int i = 0; i < m; ++i)
447 for (unsigned int j = 0; j < n; ++j)
448 op.block(i, j).vmult_add(v.block(i), u.block(j));
449 }
450 };
451
452 op.Tvmult = [&op](Domain &v, const Range &u) {
453 const unsigned int n = op.n_block_cols();
454 const unsigned int m = op.n_block_rows();
455 Assert(v.n_blocks() == n, ExcDimensionMismatch(v.n_blocks(), n));
456 Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
457
458 if (PointerComparison::equal(&v, &u))
459 {
460 const auto first_op = [&op](Range &v,
461 const Domain &u,
462 const unsigned int i,
463 const unsigned int j) {
464 op.block(j, i).Tvmult(v.block(i), u.block(j));
465 };
466
467 const auto loop_op = [&op](Range &v,
468 const Domain &u,
469 const unsigned int i,
470 const unsigned int j) {
471 op.block(j, i).Tvmult_add(v.block(i), u.block(j));
472 };
473
474 apply_with_intermediate_storage(first_op, loop_op, v, u, false);
475 }
476 else
477 {
478 for (unsigned int i = 0; i < n; ++i)
479 {
480 op.block(0, i).Tvmult(v.block(i), u.block(0));
481 for (unsigned int j = 1; j < m; ++j)
482 op.block(j, i).Tvmult_add(v.block(i), u.block(j));
483 }
484 }
485 };
486
487 op.Tvmult_add = [&op](Domain &v, const Range &u) {
488 const unsigned int n = op.n_block_cols();
489 const unsigned int m = op.n_block_rows();
490 Assert(v.n_blocks() == n, ExcDimensionMismatch(v.n_blocks(), n));
491 Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
492
493 if (PointerComparison::equal(&v, &u))
494 {
495 const auto first_op = [&op](Range &v,
496 const Domain &u,
497 const unsigned int i,
498 const unsigned int j) {
499 op.block(j, i).Tvmult(v.block(i), u.block(j));
500 };
501
502 const auto loop_op = [&op](Range &v,
503 const Domain &u,
504 const unsigned int i,
505 const unsigned int j) {
506 op.block(j, i).Tvmult_add(v.block(i), u.block(j));
507 };
508
509 apply_with_intermediate_storage(first_op, loop_op, v, u, true);
510 }
511 else
512 {
513 for (unsigned int i = 0; i < n; ++i)
514 for (unsigned int j = 0; j < m; ++j)
515 op.block(j, i).Tvmult_add(v.block(i), u.block(j));
516 }
517 };
518 }
519
520
521
535 template <typename PayloadBlockType>
537 {
538 public:
542 using BlockType = PayloadBlockType;
543
551 template <typename... Args>
552 EmptyBlockPayload(const Args &...)
553 {}
554 };
555
556 } // namespace BlockLinearOperatorImplementation
557} // namespace internal
558
559
560
577template <typename Range,
578 typename Domain,
579 typename BlockPayload,
580 typename BlockMatrixType>
582block_operator(const BlockMatrixType &block_matrix)
583{
584 using BlockType =
586
588 BlockPayload(block_matrix, block_matrix)};
589
590 return_op.n_block_rows = [&block_matrix]() -> unsigned int {
591 return block_matrix.n_block_rows();
592 };
593
594 return_op.n_block_cols = [&block_matrix]() -> unsigned int {
595 return block_matrix.n_block_cols();
596 };
597
598 return_op.block = [&block_matrix](unsigned int i,
599 unsigned int j) -> BlockType {
600 if constexpr (running_in_debug_mode())
601 {
602 const unsigned int m = block_matrix.n_block_rows();
603 const unsigned int n = block_matrix.n_block_cols();
604 AssertIndexRange(i, m);
605 AssertIndexRange(j, n);
606 }
607
608 return BlockType(block_matrix.block(i, j));
609 };
610
611 populate_linear_operator_functions(return_op);
612 return return_op;
613}
614
615
616
644template <std::size_t m,
645 std::size_t n,
646 typename Range,
647 typename Domain,
648 typename BlockPayload>
651 const std::array<std::array<LinearOperator<typename Range::BlockType,
652 typename Domain::BlockType,
653 typename BlockPayload::BlockType>,
654 n>,
655 m> &ops)
656{
657 static_assert(m > 0 && n > 0,
658 "a blocked LinearOperator must consist of at least one block");
659
660 using BlockType =
662
663 // TODO: Create block payload so that this can be initialized correctly
664 BlockLinearOperator<Range, Domain, BlockPayload> return_op{BlockPayload()};
665
666 return_op.n_block_rows = []() -> unsigned int { return m; };
667
668 return_op.n_block_cols = []() -> unsigned int { return n; };
669
670 return_op.block = [ops](unsigned int i, unsigned int j) -> BlockType {
671 AssertIndexRange(i, m);
672 AssertIndexRange(j, n);
673
674 return ops[i][j];
675 };
676
677 populate_linear_operator_functions(return_op);
678 return return_op;
679}
680
681
682
698template <typename Range = BlockVector<double>,
699 typename Domain = Range,
700 typename BlockPayload =
701 internal::BlockLinearOperatorImplementation::EmptyBlockPayload<>,
702 typename BlockMatrixType>
704block_diagonal_operator(const BlockMatrixType &block_matrix)
705{
706 using BlockType =
708
710 BlockPayload(block_matrix, block_matrix)};
711
712 return_op.n_block_rows = [&block_matrix]() -> unsigned int {
713 return block_matrix.n_block_rows();
714 };
715
716 return_op.n_block_cols = [&block_matrix]() -> unsigned int {
717 return block_matrix.n_block_cols();
718 };
719
720 return_op.block = [&block_matrix](unsigned int i,
721 unsigned int j) -> BlockType {
722 if constexpr (running_in_debug_mode())
723 {
724 const unsigned int m = block_matrix.n_block_rows();
725 const unsigned int n = block_matrix.n_block_cols();
726 Assert(m == n, ExcDimensionMismatch(m, n));
727 AssertIndexRange(i, m);
728 AssertIndexRange(j, n);
729 }
730 if (i == j)
731 return BlockType(block_matrix.block(i, j));
732 else
733 return null_operator(BlockType(block_matrix.block(i, j)));
734 };
735
736 populate_linear_operator_functions(return_op);
737 return return_op;
738}
739
740
741
759template <std::size_t m, typename Range, typename Domain, typename BlockPayload>
762 const std::array<LinearOperator<typename Range::BlockType,
763 typename Domain::BlockType,
764 typename BlockPayload::BlockType>,
765 m> &ops)
766{
767 static_assert(
768 m > 0, "a blockdiagonal LinearOperator must consist of at least one block");
769
770 using BlockType =
772
773 std::array<std::array<BlockType, m>, m> new_ops;
774
775 // This is a bit tricky. We have to make sure that the off-diagonal
776 // elements of return_op.ops are populated correctly. They must be
777 // null_operators, but with correct reinit_domain_vector and
778 // reinit_range_vector functions.
779 for (unsigned int i = 0; i < m; ++i)
780 for (unsigned int j = 0; j < m; ++j)
781 if (i == j)
782 {
783 // diagonal elements are easy:
784 new_ops[i][j] = ops[i];
785 }
786 else
787 {
788 // create a null-operator...
789 new_ops[i][j] = null_operator(ops[i]);
790 // ... and fix up reinit_domain_vector:
791 new_ops[i][j].reinit_domain_vector = ops[j].reinit_domain_vector;
792 }
793
794 return block_operator<m, m, Range, Domain>(new_ops);
795}
796
797
798
808template <std::size_t m, typename Range, typename Domain, typename BlockPayload>
811 const LinearOperator<typename Range::BlockType,
812 typename Domain::BlockType,
813 typename BlockPayload::BlockType> &op)
814{
815 static_assert(m > 0,
816 "a blockdiagonal LinearOperator must consist of at least "
817 "one block");
818
819 using BlockType =
821 std::array<BlockType, m> new_ops;
822 new_ops.fill(op);
823
824 return block_diagonal_operator(new_ops);
825}
826
827
828
869template <typename Range = BlockVector<double>,
870 typename Domain = Range,
871 typename BlockPayload =
872 internal::BlockLinearOperatorImplementation::EmptyBlockPayload<>>
877{
879 typename BlockPayload::BlockType(diagonal_inverse)};
880
881 return_op.reinit_range_vector = diagonal_inverse.reinit_range_vector;
882 return_op.reinit_domain_vector = diagonal_inverse.reinit_domain_vector;
883
884 return_op.vmult = [block_operator, diagonal_inverse](Range &v,
885 const Range &u) {
886 const unsigned int m = block_operator.n_block_rows();
887 Assert(block_operator.n_block_cols() == m,
888 ExcDimensionMismatch(block_operator.n_block_cols(), m));
889 Assert(diagonal_inverse.n_block_rows() == m,
890 ExcDimensionMismatch(diagonal_inverse.n_block_rows(), m));
891 Assert(diagonal_inverse.n_block_cols() == m,
892 ExcDimensionMismatch(diagonal_inverse.n_block_cols(), m));
893 Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
894 Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
895
896 if (m == 0)
897 return;
898
899 diagonal_inverse.block(0, 0).vmult(v.block(0), u.block(0));
900 for (unsigned int i = 1; i < m; ++i)
901 {
902 auto &dst = v.block(i);
903 dst = u.block(i);
904 dst *= -1.;
905 for (unsigned int j = 0; j < i; ++j)
906 block_operator.block(i, j).vmult_add(dst, v.block(j));
907 dst *= -1.;
908 diagonal_inverse.block(i, i).vmult(dst,
909 dst); // uses intermediate storage
910 }
911 };
912
913 return_op.vmult_add = [block_operator, diagonal_inverse](Range &v,
914 const Range &u) {
915 const unsigned int m = block_operator.n_block_rows();
916 Assert(block_operator.n_block_cols() == m,
917 ExcDimensionMismatch(block_operator.n_block_cols(), m));
918 Assert(diagonal_inverse.n_block_rows() == m,
919 ExcDimensionMismatch(diagonal_inverse.n_block_rows(), m));
920 Assert(diagonal_inverse.n_block_cols() == m,
921 ExcDimensionMismatch(diagonal_inverse.n_block_cols(), m));
922 Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
923 Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
924
925 if (m == 0)
926 return;
927
930 vector_memory);
931
932 diagonal_inverse.block(0, 0).vmult_add(v.block(0), u.block(0));
933
934 for (unsigned int i = 1; i < m; ++i)
935 {
936 diagonal_inverse.block(i, i).reinit_range_vector(
937 *tmp, /*bool omit_zeroing_entries=*/true);
938 *tmp = u.block(i);
939 *tmp *= -1.;
940 for (unsigned int j = 0; j < i; ++j)
941 block_operator.block(i, j).vmult_add(*tmp, v.block(j));
942 *tmp *= -1.;
943 diagonal_inverse.block(i, i).vmult_add(v.block(i), *tmp);
944 }
945 };
946
947 return return_op;
948}
949
950
951
986template <typename Range = BlockVector<double>,
987 typename Domain = Range,
988 typename BlockPayload =
989 internal::BlockLinearOperatorImplementation::EmptyBlockPayload<>>
994{
996 typename BlockPayload::BlockType(diagonal_inverse)};
997
998 return_op.reinit_range_vector = diagonal_inverse.reinit_range_vector;
999 return_op.reinit_domain_vector = diagonal_inverse.reinit_domain_vector;
1000
1001 return_op.vmult = [block_operator, diagonal_inverse](Range &v,
1002 const Range &u) {
1003 const unsigned int m = block_operator.n_block_rows();
1004 Assert(block_operator.n_block_cols() == m,
1005 ExcDimensionMismatch(block_operator.n_block_cols(), m));
1006 Assert(diagonal_inverse.n_block_rows() == m,
1007 ExcDimensionMismatch(diagonal_inverse.n_block_rows(), m));
1008 Assert(diagonal_inverse.n_block_cols() == m,
1009 ExcDimensionMismatch(diagonal_inverse.n_block_cols(), m));
1010 Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
1011 Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
1012
1013 if (m == 0)
1014 return;
1015
1016 diagonal_inverse.block(m - 1, m - 1).vmult(v.block(m - 1), u.block(m - 1));
1017
1018 for (int i = m - 2; i >= 0; --i)
1019 {
1020 auto &dst = v.block(i);
1021 dst = u.block(i);
1022 dst *= -1.;
1023 for (unsigned int j = i + 1; j < m; ++j)
1024 block_operator.block(i, j).vmult_add(dst, v.block(j));
1025 dst *= -1.;
1026 diagonal_inverse.block(i, i).vmult(dst,
1027 dst); // uses intermediate storage
1028 }
1029 };
1030
1031 return_op.vmult_add = [block_operator, diagonal_inverse](Range &v,
1032 const Range &u) {
1033 const unsigned int m = block_operator.n_block_rows();
1034 Assert(block_operator.n_block_cols() == m,
1035 ExcDimensionMismatch(block_operator.n_block_cols(), m));
1036 Assert(diagonal_inverse.n_block_rows() == m,
1037 ExcDimensionMismatch(diagonal_inverse.n_block_rows(), m));
1038 Assert(diagonal_inverse.n_block_cols() == m,
1039 ExcDimensionMismatch(diagonal_inverse.n_block_cols(), m));
1040 Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
1041 Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
1044 vector_memory);
1045
1046 if (m == 0)
1047 return;
1048
1049 diagonal_inverse.block(m - 1, m - 1)
1050 .vmult_add(v.block(m - 1), u.block(m - 1));
1051
1052 for (int i = m - 2; i >= 0; --i)
1053 {
1054 diagonal_inverse.block(i, i).reinit_range_vector(
1055 *tmp, /*bool omit_zeroing_entries=*/true);
1056 *tmp = u.block(i);
1057 *tmp *= -1.;
1058 for (unsigned int j = i + 1; j < m; ++j)
1059 block_operator.block(i, j).vmult_add(*tmp, v.block(j));
1060 *tmp *= -1.;
1061 diagonal_inverse.block(i, i).vmult_add(v.block(i), *tmp);
1062 }
1063 };
1064
1065 return return_op;
1066}
1067
1071
1072#endif
BlockLinearOperator< Range, Domain, BlockPayload > & operator=(const std::array< std::array< BlockType, n >, m > &ops)
BlockLinearOperator(const std::array< BlockType, m > &ops)
LinearOperator< typename Range::BlockType, typename Domain::BlockType, typename BlockPayload::BlockType > BlockType
BlockLinearOperator< Range, Domain, BlockPayload > & operator=(const std::array< BlockType, m > &ops)
std::function< BlockType(unsigned int, unsigned int)> block
BlockLinearOperator(const BlockLinearOperator< Range, Domain, BlockPayload > &)=default
BlockLinearOperator< Range, Domain, BlockPayload > & operator=(const BlockLinearOperator< Range, Domain, BlockPayload > &)=default
BlockLinearOperator< Range, Domain, BlockPayload > & operator=(const Op &op)
std::function< unsigned int()> n_block_cols
std::function< unsigned int()> n_block_rows
BlockLinearOperator(const std::array< std::array< BlockType, n >, m > &ops)
BlockLinearOperator(const BlockPayload &payload)
std::function< void(Range &v, const Domain &u)> vmult_add
std::function< void(Domain &v, const Range &u)> Tvmult
std::function< void(Domain &v, bool omit_zeroing_entries)> reinit_domain_vector
std::function< void(Range &v, const Domain &u)> vmult
std::function< void(Range &v, bool omit_zeroing_entries)> reinit_range_vector
std::function< void(Domain &v, const Range &u)> Tvmult_add
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
BlockLinearOperator< Range, Domain, BlockPayload > block_diagonal_operator(const std::array< LinearOperator< typename Range::BlockType, typename Domain::BlockType, typename BlockPayload::BlockType >, m > &)
LinearOperator< Domain, Range, typename BlockPayload::BlockType > block_forward_substitution(const BlockLinearOperator< Range, Domain, BlockPayload > &block_operator, const BlockLinearOperator< Domain, Range, BlockPayload > &diagonal_inverse)
BlockLinearOperator< Range, Domain, BlockPayload > block_operator(const std::array< std::array< LinearOperator< typename Range::BlockType, typename Domain::BlockType, typename BlockPayload::BlockType >, n >, m > &ops)
BlockLinearOperator< Range, Domain, BlockPayload > block_diagonal_operator(const std::array< LinearOperator< typename Range::BlockType, typename Domain::BlockType, typename BlockPayload::BlockType >, m > &ops)
LinearOperator< Range, Domain, Payload > null_operator(const LinearOperator< Range, Domain, Payload > &)
LinearOperator< Domain, Range, typename BlockPayload::BlockType > block_back_substitution(const BlockLinearOperator< Range, Domain, BlockPayload > &block_operator, const BlockLinearOperator< Domain, Range, BlockPayload > &diagonal_inverse)
BlockLinearOperator< Range, Domain, BlockPayload > block_diagonal_operator(const BlockMatrixType &block_matrix)
BlockLinearOperator< Range, Domain, BlockPayload > block_diagonal_operator(const LinearOperator< typename Range::BlockType, typename Domain::BlockType, typename BlockPayload::BlockType > &op)
BlockLinearOperator< Range, Domain, BlockPayload > block_operator(const BlockMatrixType &block_matrix)
BlockLinearOperator< Range, Domain, BlockPayload > block_operator(const BlockMatrixType &matrix)
void populate_linear_operator_functions(::BlockLinearOperator< Range, Domain, BlockPayload > &op)
void apply_with_intermediate_storage(const Function1 &first_op, const Function2 &loop_op, Range &v, const Domain &u, bool add)
static bool equal(const T *p1, const T *p2)