Reference documentation for deal.II version 8.4.2
block_linear_operator.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2010 - 2016 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii__block_linear_operator_h
17 #define dealii__block_linear_operator_h
18 
19 #include <deal.II/base/config.h>
20 #include <deal.II/base/exceptions.h>
21 
22 #include <deal.II/lac/linear_operator.h>
23 
24 #ifdef DEAL_II_WITH_CXX11
25 
26 DEAL_II_NAMESPACE_OPEN
27 
28 // Forward declarations:
29 
30 template <typename Number> class BlockVector;
31 
32 template <typename Range = BlockVector<double>,
33  typename Domain = Range>
35 
36 template <typename Range = BlockVector<double>,
37  typename Domain = Range,
38  typename BlockMatrixType>
40 block_operator(const BlockMatrixType &matrix);
41 
42 template <size_t m, size_t n,
43  typename Range = BlockVector<double>,
44  typename Domain = Range>
47 
48 template <size_t m,
49  typename Range = BlockVector<double>,
50  typename Domain = Range>
53 
54 template <size_t m,
55  typename Range = BlockVector<double>,
56  typename Domain = Range>
59 
60 // This is a workaround for a bug in <=gcc-4.7 that does not like partial
61 // template default values in combination with local lambda expressions [1]
62 //
63 // [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53624
64 //
65 // Forward declare functions with partial template defaults:
66 
67 template <typename Range = BlockVector<double>,
68  typename Domain = Range,
69  typename BlockMatrixType>
71 block_diagonal_operator(const BlockMatrixType &block_matrix);
72 
73 template <typename Range = BlockVector<double>,
74  typename Domain = Range>
78 
79 template <typename Range = BlockVector<double>,
80  typename Domain = Range>
84 
85 // end of workaround
86 
87 
88 
128 template <typename Range, typename Domain>
129 class BlockLinearOperator : public LinearOperator<Range, Domain>
130 {
131 public:
132 
134 
143  : LinearOperator<Range, Domain>()
144  {
145 
146  n_block_rows = []() -> unsigned int
147  {
148  Assert(false, ExcMessage("Uninitialized BlockLinearOperator<Range, Domain>::n_block_rows called"));
149  return 0;
150  };
151 
152  n_block_cols = []() -> unsigned int
153  {
154  Assert(false, ExcMessage("Uninitialized BlockLinearOperator<Range, Domain>::n_block_cols called"));
155  return 0;
156  };
157 
158  block = [](unsigned int, unsigned int) -> BlockType
159  {
160  Assert(false, ExcMessage("Uninitialized BlockLinearOperator<Range, Domain>::block called"));
161  return BlockType();
162  };
163  }
164 
169  default;
170 
176  template<typename Op>
177  BlockLinearOperator(const Op &op)
178  {
179  *this = block_operator<Range, Domain, Op>(op);
180  }
181 
187  template<size_t m, size_t n>
188  BlockLinearOperator(const std::array<std::array<BlockType, n>, m> &ops)
189  {
190  *this = block_operator<m, n, Range, Domain>(ops);
191  }
192 
198  template<size_t m>
199  BlockLinearOperator(const std::array<BlockType, m> &ops)
200  {
201  *this = block_diagonal_operator<m, Range, Domain>(ops);
202  }
203 
209 
214  template <typename Op>
216  {
217  *this = block_operator<Range, Domain, Op>(op);
218  return *this;
219  }
220 
226  template <size_t m, size_t n>
228  operator=(const std::array<std::array<BlockType, n>, m> &ops)
229  {
230  *this = block_operator<m, n, Range, Domain>(ops);
231  return *this;
232  }
233 
239  template <size_t m>
241  operator=(const std::array<BlockType, m> &ops)
242  {
243  *this = block_diagonal_operator<m, Range, Domain>(ops);
244  return *this;
245  }
246 
251  std::function<unsigned int()> n_block_rows;
252 
257  std::function<unsigned int()> n_block_cols;
258 
264  std::function<BlockType(unsigned int, unsigned int)> block;
265 };
266 
267 
268 
269 namespace internal
270 {
271  namespace BlockLinearOperator
272  {
273  // Populate the LinearOperator interfaces with the help of the
274  // BlockLinearOperator functions
275  template <typename Range, typename Domain>
276  inline void
277  populate_linear_operator_functions(
279  {
280  op.reinit_range_vector = [=](Range &v, bool omit_zeroing_entries)
281  {
282  const unsigned int m = op.n_block_rows();
283 
284  // Reinitialize the block vector to m blocks:
285  v.reinit(m);
286 
287  // And reinitialize every individual block with reinit_range_vectors:
288  for (unsigned int i = 0; i < m; ++i)
289  op.block(i, 0).reinit_range_vector(v.block(i), omit_zeroing_entries);
290 
291  v.collect_sizes();
292  };
293 
294  op.reinit_domain_vector = [=](Domain &v, bool omit_zeroing_entries)
295  {
296  const unsigned int n = op.n_block_cols();
297 
298  // Reinitialize the block vector to n blocks:
299  v.reinit(n);
300 
301  // And reinitialize every individual block with reinit_domain_vectors:
302  for (unsigned int i = 0; i < n; ++i)
303  op.block(0, i).reinit_domain_vector(v.block(i), omit_zeroing_entries);
304 
305  v.collect_sizes();
306  };
307 
308  op.vmult = [=](Range &v, const Domain &u)
309  {
310  const unsigned int m = op.n_block_rows();
311  const unsigned int n = op.n_block_cols();
312  Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
313  Assert(u.n_blocks() == n, ExcDimensionMismatch(u.n_blocks(), n));
314 
315  for (unsigned int i = 0; i < m; ++i)
316  {
317  op.block(i, 0).vmult(v.block(i), u.block(0));
318  for (unsigned int j = 1; j < n; ++j)
319  op.block(i, j).vmult_add(v.block(i), u.block(j));
320  }
321  };
322 
323  op.vmult_add = [=](Range &v, const Domain &u)
324  {
325  const unsigned int m = op.n_block_rows();
326  const unsigned int n = op.n_block_cols();
327  Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
328  Assert(u.n_blocks() == n, ExcDimensionMismatch(u.n_blocks(), n));
329 
330  for (unsigned int i = 0; i < m; ++i)
331  for (unsigned int j = 0; j < n; ++j)
332  op.block(i, j).vmult_add(v.block(i), u.block(j));
333  };
334 
335  op.Tvmult = [=](Domain &v, const Range &u)
336  {
337  const unsigned int n = op.n_block_cols();
338  const unsigned int m = op.n_block_rows();
339  Assert(v.n_blocks() == n, ExcDimensionMismatch(v.n_blocks(), n));
340  Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
341 
342  for (unsigned int i = 0; i < n; ++i)
343  {
344  op.block(0, i).Tvmult(v.block(i), u.block(0));
345  for (unsigned int j = 1; j < m; ++j)
346  op.block(j, i).Tvmult_add(v.block(i), u.block(j));
347  }
348  };
349 
350  op.Tvmult_add = [=](Domain &v, const Range &u)
351  {
352  const unsigned int n = op.n_block_cols();
353  const unsigned int m = op.n_block_rows();
354  Assert(v.n_blocks() == n, ExcDimensionMismatch(v.n_blocks(), n));
355  Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
356 
357  for (unsigned int i = 0; i < n; ++i)
358  for (unsigned int j = 0; j < m; ++j)
359  op.block(j, i).Tvmult_add(v.block(i), u.block(j));
360  };
361  }
362  } /*namespace BlockLinearOperator*/
363 } /*namespace internal*/
364 
365 
366 
371 
383 template <typename Range,
384  typename Domain,
385  typename BlockMatrixType>
387 block_operator(const BlockMatrixType &block_matrix)
388 {
390 
392 
393  return_op.n_block_rows = [&block_matrix]() -> unsigned int
394  {
395  return block_matrix.n_block_rows();
396  };
397 
398  return_op.n_block_cols = [&block_matrix]() -> unsigned int
399  {
400  return block_matrix.n_block_cols();
401  };
402 
403  return_op.block = [&block_matrix](unsigned int i, unsigned int j) -> BlockType
404  {
405 #ifdef DEBUG
406  const unsigned int m = block_matrix.n_block_rows();
407  const unsigned int n = block_matrix.n_block_cols();
408  Assert(i < m, ExcIndexRange (i, 0, m));
409  Assert(j < n, ExcIndexRange (j, 0, n));
410 #endif
411 
412  return BlockType(block_matrix.block(i, j));
413  };
414 
415  internal::BlockLinearOperator::populate_linear_operator_functions(return_op);
416  return return_op;
417 }
418 
419 
420 
448 template <size_t m, size_t n, typename Range, typename Domain>
451 {
452  static_assert(m > 0 && n > 0,
453  "a blocked LinearOperator must consist of at least one block");
454 
456 
458 
459  return_op.n_block_rows = []() -> unsigned int
460  {
461  return m;
462  };
463 
464  return_op.n_block_cols = []() -> unsigned int
465  {
466  return n;
467  };
468 
469  return_op.block = [ops](unsigned int i, unsigned int j) -> BlockType
470  {
471  Assert(i < m, ExcIndexRange (i, 0, m));
472  Assert(j < n, ExcIndexRange (j, 0, n));
473 
474  return ops[i][j];
475  };
476 
477  internal::BlockLinearOperator::populate_linear_operator_functions(return_op);
478  return return_op;
479 }
480 
481 
482 
498 template <typename Range,
499  typename Domain,
500  typename BlockMatrixType>
502 block_diagonal_operator(const BlockMatrixType &block_matrix)
503 {
505 
507 
508  return_op.n_block_rows = [&block_matrix]() -> unsigned int
509  {
510  return block_matrix.n_block_rows();
511  };
512 
513  return_op.n_block_cols = [&block_matrix]() -> unsigned int
514  {
515  return block_matrix.n_block_cols();
516  };
517 
518  return_op.block = [&block_matrix](unsigned int i, unsigned int j) -> BlockType
519  {
520 #ifdef DEBUG
521  const unsigned int m = block_matrix.n_block_rows();
522  const unsigned int n = block_matrix.n_block_cols();
523  Assert(m == n, ExcDimensionMismatch(m, n));
524  Assert(i < m, ExcIndexRange (i, 0, m));
525  Assert(j < n, ExcIndexRange (j, 0, n));
526 #endif
527  if (i == j)
528  return BlockType(block_matrix.block(i, j));
529  else
530  return null_operator(BlockType(block_matrix.block(i, j)));
531  };
532 
533  internal::BlockLinearOperator::populate_linear_operator_functions(return_op);
534  return return_op;
535 }
536 
537 
538 
556 template <size_t m, typename Range, typename Domain>
559 {
560  static_assert(m > 0,
561  "a blockdiagonal LinearOperator must consist of at least one block");
562 
564 
565  std::array<std::array<BlockType, m>, m> new_ops;
566 
567  // This is a bit tricky. We have to make sure that the off-diagonal
568  // elements of return_op.ops are populated correctly. They must be
569  // null_operators, but with correct reinit_domain_vector and
570  // reinit_range_vector functions.
571  for (unsigned int i = 0; i < m; ++i)
572  for (unsigned int j = 0; j < m; ++j)
573  if (i == j)
574  {
575  // diagonal elements are easy:
576  new_ops[i][j] = ops[i];
577  }
578  else
579  {
580  // create a null-operator...
581  new_ops[i][j] = null_operator(ops[i]);
582  // ... and fix up reinit_domain_vector:
583  new_ops[i][j].reinit_domain_vector = ops[j].reinit_domain_vector;
584  }
585 
586  return block_operator<m,m,Range,Domain>(new_ops);
587 }
588 
589 
590 
600 template <size_t m, typename Range, typename Domain>
603 {
604  static_assert(m > 0,
605  "a blockdiagonal LinearOperator must consist of at least "
606  "one block");
607 
609  std::array<BlockType, m> new_ops;
610  new_ops.fill(op);
611 
612  return block_diagonal_operator(new_ops);
613 }
614 
615 
616 
618 
622 
658 template <typename Range, typename Domain>
661  const BlockLinearOperator<Domain, Range> &diagonal_inverse)
662 {
664 
665  return_op.reinit_range_vector = diagonal_inverse.reinit_range_vector;
666  return_op.reinit_domain_vector = diagonal_inverse.reinit_domain_vector;
667 
668  return_op.vmult = [block_operator, diagonal_inverse](Range &v, const Range &u)
669  {
670  const unsigned int m = block_operator.n_block_rows();
671  Assert(block_operator.n_block_cols() == m,
672  ExcDimensionMismatch(block_operator.n_block_cols(), m));
673  Assert(diagonal_inverse.n_block_rows() == m,
674  ExcDimensionMismatch(diagonal_inverse.n_block_rows(), m));
675  Assert(diagonal_inverse.n_block_cols() == m,
676  ExcDimensionMismatch(diagonal_inverse.n_block_cols(), m));
677  Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
678  Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
679 
680  if (m == 0)
681  return;
682 
683  diagonal_inverse.block(0, 0).vmult(v.block(0), u.block(0));
684  for (unsigned int i = 1; i < m; ++i)
685  {
686  auto &dst = v.block(i);
687  dst = u.block(i);
688  dst *= -1.;
689  for (unsigned int j = 0; j < i; ++j)
690  block_operator.block(i, j).vmult_add(dst, v.block(j));
691  dst *= -1.;
692  diagonal_inverse.block(i, i).vmult(dst, dst); // uses intermediate storage
693  }
694  };
695 
696  return_op.vmult_add = [block_operator, diagonal_inverse](Range &v, const Range &u)
697  {
698  const unsigned int m = block_operator.n_block_rows();
699  Assert(block_operator.n_block_cols() == m,
700  ExcDimensionMismatch(block_operator.n_block_cols(), m));
701  Assert(diagonal_inverse.n_block_rows() == m,
702  ExcDimensionMismatch(diagonal_inverse.n_block_rows(), m));
703  Assert(diagonal_inverse.n_block_cols() == m,
704  ExcDimensionMismatch(diagonal_inverse.n_block_cols(), m));
705  Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
706  Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
707 
708  if (m == 0)
709  return;
710 
712  typename Range::BlockType *tmp = vector_memory.alloc();
713 
714  diagonal_inverse.block(0, 0).vmult_add(v.block(0), u.block(0));
715 
716  for (unsigned int i = 1; i < m; ++i)
717  {
718  diagonal_inverse.block(i, i).reinit_range_vector(*tmp, /*bool omit_zeroing_entries=*/ true);
719  *tmp = u.block(i);
720  *tmp *= -1.;
721  for (unsigned int j = 0; j < i; ++j)
722  block_operator.block(i, j).vmult_add(*tmp, v.block(j));
723  *tmp *= -1.;
724  diagonal_inverse.block(i, i).vmult_add(v.block(i),*tmp);
725  }
726 
727  vector_memory.free(tmp);
728  };
729 
730  return return_op;
731 }
732 
733 
734 
770 template <typename Range, typename Domain>
773  const BlockLinearOperator<Domain, Range> &diagonal_inverse)
774 {
776 
777  return_op.reinit_range_vector = diagonal_inverse.reinit_range_vector;
778  return_op.reinit_domain_vector = diagonal_inverse.reinit_domain_vector;
779 
780  return_op.vmult = [block_operator, diagonal_inverse](Range &v, const Range &u)
781  {
782  const unsigned int m = block_operator.n_block_rows();
783  Assert(block_operator.n_block_cols() == m,
784  ExcDimensionMismatch(block_operator.n_block_cols(), m));
785  Assert(diagonal_inverse.n_block_rows() == m,
786  ExcDimensionMismatch(diagonal_inverse.n_block_rows(), m));
787  Assert(diagonal_inverse.n_block_cols() == m,
788  ExcDimensionMismatch(diagonal_inverse.n_block_cols(), m));
789  Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
790  Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
791 
792  if (m == 0)
793  return;
794 
795  diagonal_inverse.block(m-1, m-1).vmult(v.block(m-1),u.block(m-1));
796 
797  for (int i = m - 2; i >= 0; --i)
798  {
799  auto &dst = v.block(i);
800  dst = u.block(i);
801  dst *= -1.;
802  for (unsigned int j = i + 1; j < m; ++j)
803  block_operator.block(i, j).vmult_add(dst, v.block(j));
804  dst *= -1.;
805  diagonal_inverse.block(i, i).vmult(dst, dst); // uses intermediate storage
806  }
807  };
808 
809  return_op.vmult_add = [block_operator, diagonal_inverse](Range &v, const Range &u)
810  {
811  const unsigned int m = block_operator.n_block_rows();
812  Assert(block_operator.n_block_cols() == m,
813  ExcDimensionMismatch(block_operator.n_block_cols(), m));
814  Assert(diagonal_inverse.n_block_rows() == m,
815  ExcDimensionMismatch(diagonal_inverse.n_block_rows(), m));
816  Assert(diagonal_inverse.n_block_cols() == m,
817  ExcDimensionMismatch(diagonal_inverse.n_block_cols(), m));
818  Assert(v.n_blocks() == m, ExcDimensionMismatch(v.n_blocks(), m));
819  Assert(u.n_blocks() == m, ExcDimensionMismatch(u.n_blocks(), m));
821  typename Range::BlockType *tmp = vector_memory.alloc();
822 
823  if (m == 0)
824  return;
825 
826  diagonal_inverse.block(m-1, m-1).vmult_add(v.block(m-1),u.block(m-1));
827 
828  for (int i = m - 2; i >= 0; --i)
829  {
830  diagonal_inverse.block(i, i).reinit_range_vector(*tmp, /*bool omit_zeroing_entries=*/ true);
831  *tmp = u.block(i);
832  *tmp *= -1.;
833  for (unsigned int j = i + 1; j < m; ++j)
834  block_operator.block(i, j).vmult_add(*tmp,v.block(j));
835  *tmp *= -1.;
836  diagonal_inverse.block(i, i).vmult_add(v.block(i),*tmp);
837  }
838 
839  vector_memory.free(tmp);
840  };
841 
842  return return_op;
843 }
844 
846 
847 DEAL_II_NAMESPACE_CLOSE
848 
849 #endif // DEAL_II_WITH_CXX11
850 #endif
std::function< unsigned int()> n_block_cols
BlockLinearOperator< Range, Domain > block_diagonal_operator(const BlockMatrixType &block_matrix)
::ExceptionBase & ExcMessage(std::string arg1)
BlockLinearOperator< Range, Domain > & operator=(const std::array< BlockType, m > &ops)
BlockLinearOperator< Range, Domain > block_diagonal_operator(const LinearOperator< typename Range::BlockType, typename Domain::BlockType > &op)
std::function< unsigned int()> n_block_rows
LinearOperator< Domain, Range > block_forward_substitution(const BlockLinearOperator< Range, Domain > &block_operator, const BlockLinearOperator< Domain, Range > &diagonal_inverse)
std::function< void(Range &v, bool omit_zeroing_entries)> reinit_range_vector
std::function< BlockType(unsigned int, unsigned int)> block
BlockLinearOperator(const Op &op)
BlockLinearOperator< Range, Domain > block_diagonal_operator(const std::array< LinearOperator< typename Range::BlockType, typename Domain::BlockType >, m > &ops)
std::function< void(Domain &v, const Range &u)> Tvmult_add
LinearOperator< Range, Domain > null_operator(const LinearOperator< Range, Domain > &op)
BlockLinearOperator(const std::array< BlockType, m > &ops)
virtual VectorType * alloc()
#define Assert(cond, exc)
Definition: exceptions.h:294
virtual void free(const VectorType *const)
std::function< void(Domain &v, bool omit_zeroing_entries)> reinit_domain_vector
BlockLinearOperator< Range, Domain > block_operator(const std::array< std::array< LinearOperator< typename Range::BlockType, typename Domain::BlockType >, n >, m > &ops)
BlockLinearOperator< Range, Domain > block_operator(const BlockMatrixType &block_matrix)
BlockLinearOperator< Range, Domain > & operator=(const Op &op)
BlockLinearOperator< Range, Domain > & operator=(const std::array< std::array< BlockType, n >, m > &ops)
std::function< void(Range &v, const Domain &u)> vmult
LinearOperator< Domain, Range > block_back_substitution(const BlockLinearOperator< Range, Domain > &block_operator, const BlockLinearOperator< Domain, Range > &diagonal_inverse)
std::function< void(Range &v, const Domain &u)> vmult_add
BlockLinearOperator< Range, Domain > & operator=(const BlockLinearOperator< Range, Domain > &)=default
std::function< void(Domain &v, const Range &u)> Tvmult
BlockLinearOperator(const std::array< std::array< BlockType, n >, m > &ops)