1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2007 - 2020 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.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_matrix_block_h
17 #define dealii_matrix_block_h
18 
19 #include <deal.II/base/config.h>
20 
21 #include <deal.II/algorithms/any_data.h>
22 
23 #include <deal.II/base/memory_consumption.h>
24 #include <deal.II/base/mg_level_object.h>
25 #include <deal.II/base/smartpointer.h>
26 
27 #include <deal.II/lac/block_indices.h>
28 #include <deal.II/lac/block_sparsity_pattern.h>
29 #include <deal.II/lac/full_matrix.h>
30 #include <deal.II/lac/sparse_matrix.h>
31 
32 #include <memory>
33 
34 
35 DEAL_II_NAMESPACE_OPEN
36 
37 // Forward declarations
38 #ifndef DOXYGEN
39 template <typename MatrixType>
40 class MatrixBlock;
41 #endif
42 
43 namespace internal
44 {
45   template <typename MatrixType>
46   void
47   reinit(MatrixBlock<MatrixType> &v, const BlockSparsityPattern &p);
48 
49   template <typename number>
50   void
51   reinit(MatrixBlock<dealii::SparseMatrix<number>> &v,
52          const BlockSparsityPattern &               p);
53 } // namespace internal
54 
55 /**
56  * A wrapper around a matrix object, storing the coordinates in a block matrix
57  * as well.
58  *
59  * This class is an alternative to BlockMatrixBase, if you only want to
60  * generate a single block of the system, not the whole system. Using the
61  * add() functions of this class, it is possible to use the standard
62  * assembling functions used for block matrices, but only enter in one of the
63  * blocks and still avoiding the index computations involved.  The reason for
64  * this class is, that we may need a different number of matrices for
65  * different blocks in a block system. For example, a preconditioner for the
66  * Oseen system can be built as a block system, where the pressure block is of
67  * the form <b>M</b><sup>-1</sup><b>FA</b><sup>-1</sup> with <b>M</b> the
68  * pressure mass matrix, <b>A</b> the pressure Laplacian and <b>F</b> the
69  * advection diffusion operator applied to the pressure space. Since only a
70  * single matrix is needed for the other blocks, using BlockSparseMatrix or
71  * similar would be a waste of memory.
72  *
73  * While the add() functions make a MatrixBlock appear like a block matrix for
74  * assembling, the functions vmult(), Tvmult(), vmult_add(), and Tvmult_add()
75  * make it behave like a MatrixType, when it comes to applying it to a vector.
76  * This behavior allows us to store MatrixBlock objects in vectors, for
77  * instance in MGLevelObject without extracting the #matrix first.
78  *
79  * MatrixBlock comes handy when using BlockMatrixArray. Once the MatrixBlock
80  * has been properly initialized and filled, it can be used in the simplest
81  * case as:
82  * @code
83  * MatrixBlockVector<SparseMatrix<double> > > blocks;
84  *
85  * ...
86  *
87  * BlockMatrixArray matrix (n_blocks, n_blocks);
88  *
89  * for (size_type i=0;i<blocks.size;++i)
90  *   matrix.enter(blocks.block(i).row, blocks.block(i).column,
91  * blocks.matrix(i));
92  * @endcode
93  *
94  * Here, we have not gained very much, except that we do not need to set up
95  * empty blocks in the block system.
96  *
97  * @note This class expects, that the row and column BlockIndices objects for
98  * the system are equal. If they are not, some functions will throw
99  * ExcNotImplemented.
100  *
101  * @todo Example for the product preconditioner of the pressure Schur
102  * complement.
103  *
104  * @ingroup Matrix2
105  * @ingroup vector_valued
106  *
107  * @see
108  * @ref GlossBlockLA "Block (linear algebra)"
109  */
110 template <typename MatrixType>
111 class MatrixBlock : public Subscriptor
112 {
113 public:
114   /**
115    * Declare type for container size.
116    */
117   using size_type = types::global_dof_index;
118 
119   /**
120    * Declare a type for matrix entries.
121    */
122   using value_type = typename MatrixType::value_type;
123 
124   /**
125    * Constructor rendering an uninitialized object.
126    */
127   MatrixBlock();
128 
129   /**
130    * Copy constructor.
131    */
132   MatrixBlock(const MatrixBlock<MatrixType> &M) = default;
133 
134   /**
135    * Assignment operator.
136    */
137   MatrixBlock<MatrixType> &
138   operator=(const MatrixBlock<MatrixType> &) = default;
139 
140   /**
141    * Constructor setting block coordinates, but not initializing the matrix.
142    */
143 
144   MatrixBlock(size_type i, size_type j);
145 
146   /**
147    * Reinitialize the matrix for a new BlockSparsityPattern. This adjusts the
148    * #matrix as well as the #row_indices and #column_indices.
149    *
150    * @note The row and column block structure of the sparsity pattern must be
151    * equal.
152    */
153   void
154   reinit(const BlockSparsityPattern &sparsity);
155 
156   operator MatrixType &();
157   operator const MatrixType &() const;
158 
159   /**
160    * Add <tt>value</tt> to the element (<i>i,j</i>). Throws an error if the
161    * entry does not exist or if it is in a different block.
162    */
163   void
164   add(const size_type                       i,
165       const size_type                       j,
166       const typename MatrixType::value_type value);
167 
168   /**
169    * Add all elements in a FullMatrix into sparse matrix locations given by
170    * <tt>indices</tt>. This function assumes a quadratic sparse matrix and a
171    * quadratic full_matrix.  The global locations are translated into
172    * locations in this block and ExcBlockIndexMismatch is thrown, if the
173    * global index does not point into the block referred to by #row and
174    * #column.
175    *
176    * @todo <tt>elide_zero_values</tt> is currently ignored.
177    *
178    * The optional parameter <tt>elide_zero_values</tt> can be used to specify
179    * whether zero values should be added anyway or these should be filtered
180    * away and only non-zero data is added. The default value is <tt>true</tt>,
181    * i.e., zero values won't be added into the matrix.
182    */
183   template <typename number>
184   void
185   add(const std::vector<size_type> &indices,
186       const FullMatrix<number> &    full_matrix,
187       const bool                    elide_zero_values = true);
188 
189   /**
190    * Add all elements in a FullMatrix into global locations given by
191    * <tt>row_indices</tt> and <tt>col_indices</tt>, respectively. The global
192    * locations are translated into locations in this block and
193    * ExcBlockIndexMismatch is thrown, if the global index does not point into
194    * the block referred to by #row and #column.
195    *
196    * @todo <tt>elide_zero_values</tt> is currently ignored.
197    *
198    * The optional parameter <tt>elide_zero_values</tt> can be used to specify
199    * whether zero values should be added anyway or these should be filtered
200    * away and only non-zero data is added. The default value is <tt>true</tt>,
201    * i.e., zero values won't be added into the matrix.
202    */
203   template <typename number>
204   void
205   add(const std::vector<size_type> &row_indices,
206       const std::vector<size_type> &col_indices,
207       const FullMatrix<number> &    full_matrix,
208       const bool                    elide_zero_values = true);
209 
210   /**
211    * Set several elements in the specified row of the matrix with column
212    * indices as given by <tt>col_indices</tt> to the respective value. This is
213    * the function doing the actual work for the ones adding full matrices. The
214    * global locations <tt>row_index</tt> and <tt>col_indices</tt> are
215    * translated into locations in this block and ExcBlockIndexMismatch is
216    * thrown, if the global index does not point into the block referred to by
217    * #row and #column.
218    *
219    * @todo <tt>elide_zero_values</tt> is currently ignored.
220    *
221    * The optional parameter <tt>elide_zero_values</tt> can be used to specify
222    * whether zero values should be added anyway or these should be filtered
223    * away and only non-zero data is added. The default value is <tt>true</tt>,
224    * i.e., zero values won't be added into the matrix.
225    */
226   template <typename number>
227   void
228   add(const size_type               row_index,
229       const std::vector<size_type> &col_indices,
230       const std::vector<number> &   values,
231       const bool                    elide_zero_values = true);
232 
233   /**
234    * Add an array of values given by <tt>values</tt> in the given global
235    * matrix row at columns specified by col_indices in the sparse matrix.
236    *
237    * The optional parameter <tt>elide_zero_values</tt> can be used to specify
238    * whether zero values should be added anyway or these should be filtered
239    * away and only non-zero data is added. The default value is <tt>true</tt>,
240    * i.e., zero values won't be added into the matrix.
241    */
242   template <typename number>
243   void
244   add(const size_type  row,
245       const size_type  n_cols,
246       const size_type *col_indices,
247       const number *   values,
248       const bool       elide_zero_values      = true,
249       const bool       col_indices_are_sorted = false);
250 
251   /**
252    * Matrix-vector-multiplication, forwarding to the same function in
253    * MatrixType. No index computations are done, thus, the vectors need to
254    * have sizes matching #matrix.
255    */
256   template <class VectorType>
257   void
258   vmult(VectorType &w, const VectorType &v) const;
259 
260   /**
261    * Matrix-vector-multiplication, forwarding to the same function in
262    * MatrixType. No index computations are done, thus, the vectors need to
263    * have sizes matching #matrix.
264    */
265   template <class VectorType>
266   void
267   vmult_add(VectorType &w, const VectorType &v) const;
268 
269   /**
270    * Matrix-vector-multiplication, forwarding to the same function in
271    * MatrixType. No index computations are done, thus, the vectors need to
272    * have sizes matching #matrix.
273    */
274   template <class VectorType>
275   void
276   Tvmult(VectorType &w, const VectorType &v) const;
277 
278   /**
279    * Matrix-vector-multiplication, forwarding to the same function in
280    * MatrixType. No index computations are done, thus, the vectors need to
281    * have sizes matching #matrix.
282    */
283   template <class VectorType>
284   void
285   Tvmult_add(VectorType &w, const VectorType &v) const;
286 
287   /**
288    * The memory used by this object.
289    */
290   std::size_t
291   memory_consumption() const;
292 
293   /**
294    * The block number computed from an index by using BlockIndices does not
295    * match the block coordinates stored in this object.
296    */
297   DeclException2(ExcBlockIndexMismatch,
298                  size_type,
299                  size_type,
300                  << "Block index " << arg1 << " does not match " << arg2);
301 
302   /**
303    * Row coordinate.  This is the position of the data member matrix on the
304    * global matrix.
305    */
306   size_type row;
307   /**
308    * Column coordinate.  This is the position of the data member matrix on the
309    * global matrix.
310    */
311   size_type column;
312 
313   /**
314    * The matrix itself
315    */
316   MatrixType matrix;
317 
318 private:
319   /**
320    * The row BlockIndices of the whole system. Using row(), this allows us to
321    * find the index of the first row degree of freedom for this block.
322    */
323   BlockIndices row_indices;
324   /**
325    * The column BlockIndices of the whole system. Using column(), this allows
326    * us to find the index of the first column degree of freedom for this
327    * block.
328    */
329   BlockIndices column_indices;
330 
331   template <class OTHER_MatrixType>
332   friend void
333   dealii::internal::reinit(MatrixBlock<OTHER_MatrixType> &,
334                            const BlockSparsityPattern &);
335 
336   template <typename number>
337   friend void
338   internal::reinit(MatrixBlock<dealii::SparseMatrix<number>> &v,
339                    const BlockSparsityPattern &               p);
340 };
341 
342 
343 /**
344  * A vector of MatrixBlock, which is implemented using shared pointers, in
345  * order to allow for copying and rearranging. Each matrix block can be
346  * identified by name.
347  *
348  * @relatesalso MatrixBlock
349  * @ingroup vector_valued
350  */
351 template <typename MatrixType>
352 class MatrixBlockVector : private AnyData
353 {
354 public:
355   /**
356    * Declare type for container size.
357    */
358   using size_type = types::global_dof_index;
359 
360   /**
361    * The type of object stored.
362    */
363   using value_type = MatrixBlock<MatrixType>;
364 
365   /**
366    * The pointer type used for storing the objects. We use a shard pointer,
367    * such that they get deleted automatically when not used anymore.
368    */
369   using ptr_type = std::shared_ptr<value_type>;
370 
371   /**
372    * Add a new matrix block at the position <tt>(row,column)</tt> in the block
373    * system.
374    */
375   void
376   add(size_type row, size_type column, const std::string &name);
377 
378   /**
379    * For matrices using a SparsityPattern, this function reinitializes each
380    * matrix in the vector with the correct pattern from the block system.
381    */
382   void
383   reinit(const BlockSparsityPattern &sparsity);
384 
385   /**
386    * Clear the object.
387    *
388    * Since often only clearing of the individual matrices is desired, but not
389    * removing the blocks themselves, there is an optional argument. If the
390    * argument is missing or @p false, all matrices will be empty, but the size
391    * of this object and the block positions will not change. If @p
392    * really_clean is @p true, then the object will contain no blocks at the
393    * end.
394    */
395   void
396   clear(bool really_clean = false);
397 
398   /**
399    * The memory used by this object.
400    */
401   std::size_t
402   memory_consumption() const;
403 
404   /**
405    * Access a constant reference to the block at position <i>i</i>.
406    */
407   const value_type &
408   block(size_type i) const;
409 
410   /**
411    * Access a reference to the block at position <i>i</i>.
412    */
413   value_type &
414   block(size_type i);
415 
416   /**
417    * Access the matrix at position <i>i</i> for read and write access.
418    */
419   MatrixType &
420   matrix(size_type i);
421 
422   /**
423    * import functions from private base class
424    */
425   using AnyData::name;
426   using AnyData::size;
427   using AnyData::subscribe;
428   using AnyData::unsubscribe;
429 };
430 
431 
432 /**
433  * A vector of MGLevelObject<MatrixBlock>, which is implemented using shared
434  * pointers, in order to allow for copying and rearranging. Each matrix block
435  * can be identified by name.
436  *
437  * @relatesalso MatrixBlock
438  * @ingroup vector_valued
439  */
440 template <typename MatrixType>
441 class MGMatrixBlockVector : public Subscriptor
442 {
443 public:
444   /**
445    * Declare type for container size.
446    */
447   using size_type = types::global_dof_index;
448 
449   /**
450    * The type of object stored.
451    */
452   using value_type = MGLevelObject<MatrixBlock<MatrixType>>;
453   /**
454    * Constructor, determining which matrices should be stored.
455    *
456    * If <tt>edge_matrices</tt> is true, then objects for edge matrices for
457    * discretizations with degrees of freedom on faces are allocated.
458    *
459    * If <tt>edge_flux_matrices</tt> is true, then objects for DG fluxes on the
460    * refinement edge are allocated.
461    */
462   MGMatrixBlockVector(const bool edge_matrices      = false,
463                       const bool edge_flux_matrices = false);
464 
465   /**
466    * The number of blocks.
467    */
468   unsigned int
469   size() const;
470 
471   /**
472    * Add a new matrix block at the position <tt>(row,column)</tt> in the block
473    * system. The third argument allows to give the matrix a name for later
474    * identification.
475    */
476   void
477   add(size_type row, size_type column, const std::string &name);
478 
479   /**
480    * For matrices using a SparsityPattern, this function reinitializes each
481    * matrix in the vector with the correct pattern from the block system.
482    *
483    * This function reinitializes the level matrices.
484    */
485   void
486   reinit_matrix(const MGLevelObject<BlockSparsityPattern> &sparsity);
487   /**
488    * For matrices using a SparsityPattern, this function reinitializes each
489    * matrix in the vector with the correct pattern from the block system.
490    *
491    * This function reinitializes the matrices for degrees of freedom on the
492    * refinement edge.
493    */
494   void
495   reinit_edge(const MGLevelObject<BlockSparsityPattern> &sparsity);
496   /**
497    * For matrices using a SparsityPattern, this function reinitializes each
498    * matrix in the vector with the correct pattern from the block system.
499    *
500    * This function reinitializes the flux matrices over the refinement edge.
501    */
502   void
503   reinit_edge_flux(const MGLevelObject<BlockSparsityPattern> &sparsity);
504 
505   /**
506    * Clear the object.
507    *
508    * Since often only clearing of the individual matrices is desired, but not
509    * removing the blocks themselves, there is an optional argument. If the
510    * argument is missing or @p false, all matrices will be empty, but the size
511    * of this object and the block positions will not change. If @p
512    * really_clean is @p true, then the object will contain no blocks at the
513    * end.
514    */
515   void
516   clear(bool really_clean = false);
517 
518   /**
519    * Access a constant reference to the matrix block at position <i>i</i>.
520    */
521   const value_type &
522   block(size_type i) const;
523 
524   /**
525    * Access a reference to the matrix block at position <i>i</i>.
526    */
527   value_type &
528   block(size_type i);
529 
530   /**
531    * Access a constant reference to the edge matrix block at position
532    * <i>i</i>.
533    */
534   const value_type &
535   block_in(size_type i) const;
536 
537   /**
538    * Access a reference to the edge matrix block at position <i>i</i>.
539    */
540   value_type &
541   block_in(size_type i);
542 
543   /**
544    * Access a constant reference to the edge matrix block at position
545    * <i>i</i>.
546    */
547   const value_type &
548   block_out(size_type i) const;
549 
550   /**
551    * Access a reference to the edge matrix block at position <i>i</i>.
552    */
553   value_type &
554   block_out(size_type i);
555 
556   /**
557    * Access a constant reference to the  edge flux matrix block at position
558    * <i>i</i>.
559    */
560   const value_type &
561   block_up(size_type i) const;
562 
563   /**
564    * Access a reference to the  edge flux matrix block at position <i>i</i>.
565    */
566   value_type &
567   block_up(size_type i);
568 
569   /**
570    * Access a constant reference to the  edge flux matrix block at position
571    * <i>i</i>.
572    */
573   const value_type &
574   block_down(size_type i) const;
575 
576   /**
577    * Access a reference to the edge flux matrix block at position <i>i</i>.
578    */
579   value_type &
580   block_down(size_type i);
581 
582   /**
583    * The memory used by this object.
584    */
585   std::size_t
586   memory_consumption() const;
587 
588 private:
589   /// Clear one of the matrix objects
590   void
591   clear_object(AnyData &);
592 
593   /// Flag for storing matrices_in and matrices_out
594   const bool edge_matrices;
595 
596   /// Flag for storing flux_matrices_up and flux_matrices_down
597   const bool edge_flux_matrices;
598 
599   /// The level matrices
600   AnyData matrices;
601   /// The matrix from the interior of a level to the refinement edge
602   AnyData matrices_in;
603   /// The matrix from the refinement edge to the interior of a level
604   AnyData matrices_out;
605   /// The DG flux from a level to the lower level
606   AnyData flux_matrices_down;
607   /// The DG flux from the lower level to a level
608   AnyData flux_matrices_up;
609 };
610 
611 
612 //----------------------------------------------------------------------//
613 
614 namespace internal
615 {
616   template <typename MatrixType>
617   void
reinit(MatrixBlock<MatrixType> & v,const BlockSparsityPattern & p)618   reinit(MatrixBlock<MatrixType> &v, const BlockSparsityPattern &p)
619   {
620     v.row_indices    = p.get_row_indices();
621     v.column_indices = p.get_column_indices();
622   }
623 
624 
625   template <typename number>
626   void
reinit(MatrixBlock<dealii::SparseMatrix<number>> & v,const BlockSparsityPattern & p)627   reinit(MatrixBlock<dealii::SparseMatrix<number>> &v,
628          const BlockSparsityPattern &               p)
629   {
630     v.row_indices    = p.get_row_indices();
631     v.column_indices = p.get_column_indices();
632     v.matrix.reinit(p.block(v.row, v.column));
633   }
634 } // namespace internal
635 
636 
637 template <typename MatrixType>
MatrixBlock()638 inline MatrixBlock<MatrixType>::MatrixBlock()
639   : row(numbers::invalid_size_type)
640   , column(numbers::invalid_size_type)
641 {}
642 
643 
644 template <typename MatrixType>
MatrixBlock(size_type i,size_type j)645 inline MatrixBlock<MatrixType>::MatrixBlock(size_type i, size_type j)
646   : row(i)
647   , column(j)
648 {}
649 
650 
651 template <typename MatrixType>
652 inline void
reinit(const BlockSparsityPattern & sparsity)653 MatrixBlock<MatrixType>::reinit(const BlockSparsityPattern &sparsity)
654 {
655   internal::reinit(*this, sparsity);
656 }
657 
658 
659 template <typename MatrixType>
660 inline MatrixBlock<MatrixType>::operator MatrixType &()
661 {
662   return matrix;
663 }
664 
665 
666 template <typename MatrixType>
667 inline MatrixBlock<MatrixType>::operator const MatrixType &() const
668 {
669   return matrix;
670 }
671 
672 
673 template <typename MatrixType>
674 inline void
add(const size_type gi,const size_type gj,const typename MatrixType::value_type value)675 MatrixBlock<MatrixType>::add(const size_type                       gi,
676                              const size_type                       gj,
677                              const typename MatrixType::value_type value)
678 {
679   Assert(row_indices.size() != 0, ExcNotInitialized());
680   Assert(column_indices.size() != 0, ExcNotInitialized());
681 
682   const std::pair<unsigned int, size_type> bi = row_indices.global_to_local(gi);
683   const std::pair<unsigned int, size_type> bj =
684     column_indices.global_to_local(gj);
685 
686   Assert(bi.first == row, ExcBlockIndexMismatch(bi.first, row));
687   Assert(bj.first == column, ExcBlockIndexMismatch(bj.first, column));
688 
689   matrix.add(bi.second, bj.second, value);
690 }
691 
692 
693 template <typename MatrixType>
694 template <typename number>
695 inline void
add(const std::vector<size_type> & r_indices,const std::vector<size_type> & c_indices,const FullMatrix<number> & values,const bool elide_zero_values)696 MatrixBlock<MatrixType>::add(const std::vector<size_type> &r_indices,
697                              const std::vector<size_type> &c_indices,
698                              const FullMatrix<number> &    values,
699                              const bool                    elide_zero_values)
700 {
701   Assert(row_indices.size() != 0, ExcNotInitialized());
702   Assert(column_indices.size() != 0, ExcNotInitialized());
703 
704   AssertDimension(r_indices.size(), values.m());
705   AssertDimension(c_indices.size(), values.n());
706 
707   for (size_type i = 0; i < row_indices.size(); ++i)
708     add(r_indices[i],
709         c_indices.size(),
710         c_indices.data(),
711         &values(i, 0),
712         elide_zero_values);
713 }
714 
715 
716 template <typename MatrixType>
717 template <typename number>
718 inline void
add(const size_type b_row,const size_type n_cols,const size_type * col_indices,const number * values,const bool,const bool)719 MatrixBlock<MatrixType>::add(const size_type  b_row,
720                              const size_type  n_cols,
721                              const size_type *col_indices,
722                              const number *   values,
723                              const bool,
724                              const bool)
725 {
726   Assert(row_indices.size() != 0, ExcNotInitialized());
727   Assert(column_indices.size() != 0, ExcNotInitialized());
728 
729   const std::pair<unsigned int, size_type> bi =
730     row_indices.global_to_local(b_row);
731 
732   // In debug mode, we check whether
733   // all indices are in the correct
734   // block.
735 
736   // Actually, for the time being, we
737   // leave it at this. While it may
738   // not be the most efficient way,
739   // it is at least thread safe.
740   //#ifdef DEBUG
741   Assert(bi.first == row, ExcBlockIndexMismatch(bi.first, row));
742 
743   for (size_type j = 0; j < n_cols; ++j)
744     {
745       const std::pair<unsigned int, size_type> bj =
746         column_indices.global_to_local(col_indices[j]);
747       Assert(bj.first == column, ExcBlockIndexMismatch(bj.first, column));
748 
749       matrix.add(bi.second, bj.second, values[j]);
750     }
751   //#endif
752 }
753 
754 
755 template <typename MatrixType>
756 template <typename number>
757 inline void
add(const std::vector<size_type> & indices,const FullMatrix<number> & values,const bool elide_zero_values)758 MatrixBlock<MatrixType>::add(const std::vector<size_type> &indices,
759                              const FullMatrix<number> &    values,
760                              const bool                    elide_zero_values)
761 {
762   Assert(row_indices.size() != 0, ExcNotInitialized());
763   Assert(column_indices.size() != 0, ExcNotInitialized());
764 
765   AssertDimension(indices.size(), values.m());
766   Assert(values.n() == values.m(), ExcNotQuadratic());
767 
768   for (size_type i = 0; i < indices.size(); ++i)
769     add(indices[i],
770         indices.size(),
771         indices.data(),
772         &values(i, 0),
773         elide_zero_values);
774 }
775 
776 
777 
778 template <typename MatrixType>
779 template <typename number>
780 inline void
add(const size_type row,const std::vector<size_type> & col_indices,const std::vector<number> & values,const bool elide_zero_values)781 MatrixBlock<MatrixType>::add(const size_type               row,
782                              const std::vector<size_type> &col_indices,
783                              const std::vector<number> &   values,
784                              const bool                    elide_zero_values)
785 {
786   Assert(row_indices.size() != 0, ExcNotInitialized());
787   Assert(column_indices.size() != 0, ExcNotInitialized());
788 
789   AssertDimension(col_indices.size(), values.size());
790   add(row,
791       col_indices.size(),
792       col_indices.data(),
793       values.data(),
794       elide_zero_values);
795 }
796 
797 
798 template <typename MatrixType>
799 template <class VectorType>
800 inline void
vmult(VectorType & w,const VectorType & v)801 MatrixBlock<MatrixType>::vmult(VectorType &w, const VectorType &v) const
802 {
803   matrix.vmult(w, v);
804 }
805 
806 
807 template <typename MatrixType>
808 template <class VectorType>
809 inline void
vmult_add(VectorType & w,const VectorType & v)810 MatrixBlock<MatrixType>::vmult_add(VectorType &w, const VectorType &v) const
811 {
812   matrix.vmult_add(w, v);
813 }
814 
815 
816 template <typename MatrixType>
817 template <class VectorType>
818 inline void
Tvmult(VectorType & w,const VectorType & v)819 MatrixBlock<MatrixType>::Tvmult(VectorType &w, const VectorType &v) const
820 {
821   matrix.Tvmult(w, v);
822 }
823 
824 
825 template <typename MatrixType>
826 template <class VectorType>
827 inline void
Tvmult_add(VectorType & w,const VectorType & v)828 MatrixBlock<MatrixType>::Tvmult_add(VectorType &w, const VectorType &v) const
829 {
830   matrix.Tvmult_add(w, v);
831 }
832 
833 
834 template <typename MatrixType>
835 inline std::size_t
memory_consumption()836 MatrixBlock<MatrixType>::memory_consumption() const
837 {
838   return (sizeof(*this) + MemoryConsumption::memory_consumption(matrix) -
839           sizeof(matrix));
840 }
841 
842 //----------------------------------------------------------------------//
843 
844 template <typename MatrixType>
845 inline void
add(size_type row,size_type column,const std::string & name)846 MatrixBlockVector<MatrixType>::add(size_type          row,
847                                    size_type          column,
848                                    const std::string &name)
849 {
850   ptr_type p(new value_type(row, column));
851   AnyData::add(p, name);
852 }
853 
854 
855 template <typename MatrixType>
856 inline void
reinit(const BlockSparsityPattern & sparsity)857 MatrixBlockVector<MatrixType>::reinit(const BlockSparsityPattern &sparsity)
858 {
859   for (size_type i = 0; i < this->size(); ++i)
860     {
861       block(i).reinit(sparsity);
862     }
863 }
864 
865 
866 template <typename MatrixType>
867 inline void
clear(bool really_clean)868 MatrixBlockVector<MatrixType>::clear(bool really_clean)
869 {
870   if (really_clean)
871     {
872       Assert(false, ExcNotImplemented());
873     }
874   else
875     {
876       for (size_type i = 0; i < this->size(); ++i)
877         matrix(i).clear();
878     }
879 }
880 
881 
882 
883 template <typename MatrixType>
884 inline const MatrixBlock<MatrixType> &
block(size_type i)885 MatrixBlockVector<MatrixType>::block(size_type i) const
886 {
887   return *this->read<ptr_type>(i);
888 }
889 
890 
891 template <typename MatrixType>
892 inline MatrixBlock<MatrixType> &
block(size_type i)893 MatrixBlockVector<MatrixType>::block(size_type i)
894 {
895   return *this->entry<ptr_type>(i);
896 }
897 
898 
899 template <typename MatrixType>
900 inline MatrixType &
matrix(size_type i)901 MatrixBlockVector<MatrixType>::matrix(size_type i)
902 {
903   return this->entry<ptr_type>(i)->matrix;
904 }
905 
906 
907 
908 //----------------------------------------------------------------------//
909 
910 template <typename MatrixType>
MGMatrixBlockVector(const bool e,const bool f)911 inline MGMatrixBlockVector<MatrixType>::MGMatrixBlockVector(const bool e,
912                                                             const bool f)
913   : edge_matrices(e)
914   , edge_flux_matrices(f)
915 {}
916 
917 
918 template <typename MatrixType>
919 inline unsigned int
size()920 MGMatrixBlockVector<MatrixType>::size() const
921 {
922   return matrices.size();
923 }
924 
925 
926 template <typename MatrixType>
927 inline void
add(size_type row,size_type column,const std::string & name)928 MGMatrixBlockVector<MatrixType>::add(size_type          row,
929                                      size_type          column,
930                                      const std::string &name)
931 {
932   MGLevelObject<MatrixBlock<MatrixType>> p(0, 1);
933   p[0].row    = row;
934   p[0].column = column;
935 
936   matrices.add(p, name);
937   if (edge_matrices)
938     {
939       matrices_in.add(p, name);
940       matrices_out.add(p, name);
941     }
942   if (edge_flux_matrices)
943     {
944       flux_matrices_up.add(p, name);
945       flux_matrices_down.add(p, name);
946     }
947 }
948 
949 
950 template <typename MatrixType>
951 inline const MGLevelObject<MatrixBlock<MatrixType>> &
block(size_type i)952 MGMatrixBlockVector<MatrixType>::block(size_type i) const
953 {
954   return *matrices.read<const MGLevelObject<MatrixType> *>(i);
955 }
956 
957 
958 template <typename MatrixType>
959 inline MGLevelObject<MatrixBlock<MatrixType>> &
block(size_type i)960 MGMatrixBlockVector<MatrixType>::block(size_type i)
961 {
962   return *matrices.entry<MGLevelObject<MatrixType> *>(i);
963 }
964 
965 
966 template <typename MatrixType>
967 inline const MGLevelObject<MatrixBlock<MatrixType>> &
block_in(size_type i)968 MGMatrixBlockVector<MatrixType>::block_in(size_type i) const
969 {
970   return *matrices_in.read<const MGLevelObject<MatrixType> *>(i);
971 }
972 
973 
974 template <typename MatrixType>
975 inline MGLevelObject<MatrixBlock<MatrixType>> &
block_in(size_type i)976 MGMatrixBlockVector<MatrixType>::block_in(size_type i)
977 {
978   return *matrices_in.entry<MGLevelObject<MatrixType> *>(i);
979 }
980 
981 
982 template <typename MatrixType>
983 inline const MGLevelObject<MatrixBlock<MatrixType>> &
block_out(size_type i)984 MGMatrixBlockVector<MatrixType>::block_out(size_type i) const
985 {
986   return *matrices_out.read<const MGLevelObject<MatrixType> *>(i);
987 }
988 
989 
990 template <typename MatrixType>
991 inline MGLevelObject<MatrixBlock<MatrixType>> &
block_out(size_type i)992 MGMatrixBlockVector<MatrixType>::block_out(size_type i)
993 {
994   return *matrices_out.entry<MGLevelObject<MatrixType> *>(i);
995 }
996 
997 
998 template <typename MatrixType>
999 inline const MGLevelObject<MatrixBlock<MatrixType>> &
block_up(size_type i)1000 MGMatrixBlockVector<MatrixType>::block_up(size_type i) const
1001 {
1002   return *flux_matrices_up.read<const MGLevelObject<MatrixType> *>(i);
1003 }
1004 
1005 
1006 template <typename MatrixType>
1007 inline MGLevelObject<MatrixBlock<MatrixType>> &
block_up(size_type i)1008 MGMatrixBlockVector<MatrixType>::block_up(size_type i)
1009 {
1010   return *flux_matrices_up.entry<MGLevelObject<MatrixType> *>(i);
1011 }
1012 
1013 
1014 template <typename MatrixType>
1015 inline const MGLevelObject<MatrixBlock<MatrixType>> &
block_down(size_type i)1016 MGMatrixBlockVector<MatrixType>::block_down(size_type i) const
1017 {
1018   return *flux_matrices_down.read<const MGLevelObject<MatrixType> *>(i);
1019 }
1020 
1021 
1022 template <typename MatrixType>
1023 inline MGLevelObject<MatrixBlock<MatrixType>> &
block_down(size_type i)1024 MGMatrixBlockVector<MatrixType>::block_down(size_type i)
1025 {
1026   return *flux_matrices_down.entry<MGLevelObject<MatrixType> *>(i);
1027 }
1028 
1029 
1030 template <typename MatrixType>
1031 inline void
reinit_matrix(const MGLevelObject<BlockSparsityPattern> & sparsity)1032 MGMatrixBlockVector<MatrixType>::reinit_matrix(
1033   const MGLevelObject<BlockSparsityPattern> &sparsity)
1034 {
1035   for (size_type i = 0; i < this->size(); ++i)
1036     {
1037       MGLevelObject<MatrixBlock<MatrixType>> &o   = block(i);
1038       const size_type                         row = o[o.min_level()].row;
1039       const size_type                         col = o[o.min_level()].column;
1040 
1041       o.resize(sparsity.min_level(), sparsity.max_level());
1042       for (size_type level = o.min_level(); level <= o.max_level(); ++level)
1043         {
1044           o[level].row    = row;
1045           o[level].column = col;
1046           internal::reinit(o[level], sparsity[level]);
1047         }
1048     }
1049 }
1050 
1051 
1052 template <typename MatrixType>
1053 inline void
reinit_edge(const MGLevelObject<BlockSparsityPattern> & sparsity)1054 MGMatrixBlockVector<MatrixType>::reinit_edge(
1055   const MGLevelObject<BlockSparsityPattern> &sparsity)
1056 {
1057   for (size_type i = 0; i < this->size(); ++i)
1058     {
1059       MGLevelObject<MatrixBlock<MatrixType>> &o   = block(i);
1060       const size_type                         row = o[o.min_level()].row;
1061       const size_type                         col = o[o.min_level()].column;
1062 
1063       block_in(i).resize(sparsity.min_level(), sparsity.max_level());
1064       block_out(i).resize(sparsity.min_level(), sparsity.max_level());
1065       for (size_type level = o.min_level(); level <= o.max_level(); ++level)
1066         {
1067           block_in(i)[level].row    = row;
1068           block_in(i)[level].column = col;
1069           internal::reinit(block_in(i)[level], sparsity[level]);
1070           block_out(i)[level].row    = row;
1071           block_out(i)[level].column = col;
1072           internal::reinit(block_out(i)[level], sparsity[level]);
1073         }
1074     }
1075 }
1076 
1077 
1078 template <typename MatrixType>
1079 inline void
reinit_edge_flux(const MGLevelObject<BlockSparsityPattern> & sparsity)1080 MGMatrixBlockVector<MatrixType>::reinit_edge_flux(
1081   const MGLevelObject<BlockSparsityPattern> &sparsity)
1082 {
1083   for (size_type i = 0; i < this->size(); ++i)
1084     {
1085       MGLevelObject<MatrixBlock<MatrixType>> &o   = block(i);
1086       const size_type                         row = o[o.min_level()].row;
1087       const size_type                         col = o[o.min_level()].column;
1088 
1089       block_up(i).resize(sparsity.min_level(), sparsity.max_level());
1090       block_down(i).resize(sparsity.min_level(), sparsity.max_level());
1091       for (size_type level = o.min_level(); level <= o.max_level(); ++level)
1092         {
1093           block_up(i)[level].row    = row;
1094           block_up(i)[level].column = col;
1095           internal::reinit(block_up(i)[level], sparsity[level]);
1096           block_down(i)[level].row    = row;
1097           block_down(i)[level].column = col;
1098           internal::reinit(block_down(i)[level], sparsity[level]);
1099         }
1100     }
1101 }
1102 
1103 
1104 template <typename MatrixType>
1105 inline void
clear_object(AnyData & mo)1106 MGMatrixBlockVector<MatrixType>::clear_object(AnyData &mo)
1107 {
1108   for (size_type i = 0; i < mo.size(); ++i)
1109     {
1110       MGLevelObject<MatrixBlock<MatrixType>> &o =
1111         mo.entry<MGLevelObject<MatrixType> *>(i);
1112       for (size_type level = o.min_level(); level <= o.max_level(); ++level)
1113         o[level].matrix.clear();
1114     }
1115 }
1116 
1117 
1118 template <typename MatrixType>
1119 inline void
clear(bool really_clean)1120 MGMatrixBlockVector<MatrixType>::clear(bool really_clean)
1121 {
1122   if (really_clean)
1123     {
1124       Assert(false, ExcNotImplemented());
1125     }
1126   else
1127     {
1128       clear_object(matrices);
1129       clear_object(matrices_in);
1130       clear_object(matrices_out);
1131       clear_object(flux_matrices_up);
1132       clear_object(flux_matrices_down);
1133     }
1134 }
1135 
1136 
1137 
1138 DEAL_II_NAMESPACE_CLOSE
1139 
1140 #endif
1141