1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 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_block_vector_h
17 #define dealii_block_vector_h
18 
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/base/exceptions.h>
23 
24 #include <deal.II/lac/block_indices.h>
25 #include <deal.II/lac/block_vector_base.h>
26 #include <deal.II/lac/vector_operation.h>
27 #include <deal.II/lac/vector_type_traits.h>
28 
29 #include <cstdio>
30 #include <vector>
31 
32 DEAL_II_NAMESPACE_OPEN
33 
34 
35 // Forward declaration
36 #ifndef DOXYGEN
37 #  ifdef DEAL_II_WITH_TRILINOS
38 namespace TrilinosWrappers
39 {
40   namespace MPI
41   {
42     class BlockVector;
43   }
44 } // namespace TrilinosWrappers
45 #  endif
46 #endif
47 
48 
49 /*! @addtogroup Vectors
50  *@{
51  */
52 
53 
54 /**
55  * An implementation of block vectors based on deal.II vectors. While the base
56  * class provides for most of the interface, this class handles the actual
57  * allocation of vectors and provides functions that are specific to the
58  * underlying vector type.
59  *
60  * @note Instantiations for this template are provided for <tt>@<float@> and
61  * @<double@></tt>; others can be generated in application programs (see the
62  * section on
63  * @ref Instantiations
64  * in the manual).
65  *
66  * @see
67  * @ref GlossBlockLA "Block (linear algebra)"
68  */
69 template <typename Number>
70 class BlockVector : public BlockVectorBase<Vector<Number>>
71 {
72 public:
73   /**
74    * Typedef the base class for simpler access to its own alias.
75    */
76   using BaseClass = BlockVectorBase<Vector<Number>>;
77 
78   /**
79    * Typedef the type of the underlying vector.
80    */
81   using BlockType = typename BaseClass::BlockType;
82 
83   /**
84    * Import the alias from the base class.
85    */
86   using value_type      = typename BaseClass::value_type;
87   using real_type       = typename BaseClass::real_type;
88   using pointer         = typename BaseClass::pointer;
89   using const_pointer   = typename BaseClass::const_pointer;
90   using reference       = typename BaseClass::reference;
91   using const_reference = typename BaseClass::const_reference;
92   using size_type       = typename BaseClass::size_type;
93   using iterator        = typename BaseClass::iterator;
94   using const_iterator  = typename BaseClass::const_iterator;
95 
96   /**
97    * Constructor. There are three ways to use this constructor. First, without
98    * any arguments, it generates an object with no blocks. Given one argument,
99    * it initializes <tt>n_blocks</tt> blocks, but these blocks have size zero.
100    * The third variant finally initializes all blocks to the same size
101    * <tt>block_size</tt>.
102    *
103    * Confer the other constructor further down if you intend to use blocks of
104    * different sizes.
105    */
106   explicit BlockVector(const unsigned int n_blocks   = 0,
107                        const size_type    block_size = 0);
108 
109   /**
110    * Copy Constructor. Dimension set to that of @p v, all components are
111    * copied from @p v.
112    */
113   BlockVector(const BlockVector<Number> &V);
114 
115 
116   /**
117    * Move constructor. Creates a new vector by stealing the internal data of
118    * the given argument vector.
119    */
120   BlockVector(BlockVector<Number> && /*v*/) noexcept = default;
121 
122   /**
123    * Copy constructor taking a BlockVector of another data type. This will
124    * fail if there is no conversion path from <tt>OtherNumber</tt> to
125    * <tt>Number</tt>. Note that you may lose accuracy when copying to a
126    * BlockVector with data elements with less accuracy.
127    *
128    * Older versions of gcc did not honor the @p explicit keyword on template
129    * constructors. In such cases, it is easy to accidentally write code that
130    * can be very inefficient, since the compiler starts performing hidden
131    * conversions. To avoid this, this function is disabled if we have detected
132    * a broken compiler during configuration.
133    */
134   template <typename OtherNumber>
135   explicit BlockVector(const BlockVector<OtherNumber> &v);
136 
137 #ifdef DEAL_II_WITH_TRILINOS
138   /**
139    * A copy constructor taking a (parallel) Trilinos block vector and copying
140    * it into the deal.II own format.
141    */
142   BlockVector(const TrilinosWrappers::MPI::BlockVector &v);
143 
144 #endif
145   /**
146    * Constructor. Set the number of blocks to <tt>block_sizes.size()</tt> and
147    * initialize each block with <tt>block_sizes[i]</tt> zero elements.
148    */
149   BlockVector(const std::vector<size_type> &block_sizes);
150 
151   /**
152    * Constructor. Initialize vector to the structure found in the BlockIndices
153    * argument.
154    */
155   BlockVector(const BlockIndices &block_indices);
156 
157   /**
158    * Constructor. Set the number of blocks to <tt>block_sizes.size()</tt>.
159    * Initialize the vector with the elements pointed to by the range of
160    * iterators given as second and third argument. Apart from the first
161    * argument, this constructor is in complete analogy to the respective
162    * constructor of the <tt>std::vector</tt> class, but the first argument is
163    * needed in order to know how to subdivide the block vector into different
164    * blocks.
165    */
166   template <typename InputIterator>
167   BlockVector(const std::vector<size_type> &block_sizes,
168               const InputIterator           first,
169               const InputIterator           end);
170 
171   /**
172    * Destructor. Clears memory
173    */
174   ~BlockVector() override = default;
175 
176   /**
177    * Call the compress() function on all the subblocks.
178    *
179    * This functionality only needs to be called if using MPI based vectors and
180    * exists in other objects for compatibility.
181    *
182    * See
183    * @ref GlossCompress "Compressing distributed objects"
184    * for more information.
185    */
186   void
187   compress(::dealii::VectorOperation::values operation =
188              ::dealii::VectorOperation::unknown);
189 
190   /**
191    * Returns `false` as this is a serial block vector.
192    *
193    * This functionality only needs to be called if using MPI based vectors and
194    * exists in other objects for compatibility.
195    */
196   bool
197   has_ghost_elements() const;
198 
199   /**
200    * Copy operator: fill all components of the vector with the given scalar
201    * value.
202    */
203   BlockVector &
204   operator=(const value_type s);
205 
206   /**
207    * Copy operator for arguments of the same type. Resize the present vector
208    * if necessary.
209    */
210   BlockVector<Number> &
211   operator=(const BlockVector<Number> &v);
212 
213   /**
214    * Move the given vector. This operator replaces the present vector with
215    * the contents of the given argument vector.
216    */
217   BlockVector<Number> &
218   operator=(BlockVector<Number> && /*v*/) = default; // NOLINT
219 
220   /**
221    * Copy operator for template arguments of different types. Resize the
222    * present vector if necessary.
223    */
224   template <class Number2>
225   BlockVector<Number> &
226   operator=(const BlockVector<Number2> &V);
227 
228   /**
229    * Copy a regular vector into a block vector.
230    */
231   BlockVector<Number> &
232   operator=(const Vector<Number> &V);
233 
234 #ifdef DEAL_II_WITH_TRILINOS
235   /**
236    * A copy constructor from a Trilinos block vector to a deal.II block
237    * vector.
238    */
239   BlockVector<Number> &
240   operator=(const TrilinosWrappers::MPI::BlockVector &V);
241 #endif
242 
243   /**
244    * Reinitialize the BlockVector to contain <tt>n_blocks</tt> blocks of size
245    * <tt>block_size</tt> each.
246    *
247    * If the second argument is left at its default value, then the block
248    * vector allocates the specified number of blocks but leaves them at zero
249    * size. You then need to later reinitialize the individual blocks, and call
250    * collect_sizes() to update the block system's knowledge of its individual
251    * block's sizes.
252    *
253    * If <tt>omit_zeroing_entries==false</tt>, the vector is filled with zeros.
254    */
255   void
256   reinit(const unsigned int n_blocks,
257          const size_type    block_size           = 0,
258          const bool         omit_zeroing_entries = false);
259 
260   /**
261    * Reinitialize the BlockVector such that it contains
262    * <tt>block_sizes.size()</tt> blocks. Each block is reinitialized to
263    * dimension <tt>block_sizes[i]</tt>.
264    *
265    * If the number of blocks is the same as before this function was called,
266    * all vectors remain the same and reinit() is called for each vector.
267    *
268    * If <tt>omit_zeroing_entries==false</tt>, the vector is filled with zeros.
269    *
270    * Note that you must call this (or the other reinit() functions) function,
271    * rather than calling the reinit() functions of an individual block, to
272    * allow the block vector to update its caches of vector sizes. If you call
273    * reinit() on one of the blocks, then subsequent actions on this object may
274    * yield unpredictable results since they may be routed to the wrong block.
275    */
276   void
277   reinit(const std::vector<size_type> &block_sizes,
278          const bool                    omit_zeroing_entries = false);
279 
280   /**
281    * Reinitialize the BlockVector to reflect the structure found in
282    * BlockIndices.
283    *
284    * If the number of blocks is the same as before this function was called,
285    * all vectors remain the same and reinit() is called for each vector.
286    *
287    * If <tt>omit_zeroing_entries==false</tt>, the vector is filled with zeros.
288    */
289   void
290   reinit(const BlockIndices &block_indices,
291          const bool          omit_zeroing_entries = false);
292 
293   /**
294    * Change the dimension to that of the vector <tt>V</tt>. The same applies
295    * as for the other reinit() function.
296    *
297    * The elements of <tt>V</tt> are not copied, i.e.  this function is the
298    * same as calling <tt>reinit (V.size(), omit_zeroing_entries)</tt>.
299    *
300    * Note that you must call this (or the other reinit() functions) function,
301    * rather than calling the reinit() functions of an individual block, to
302    * allow the block vector to update its caches of vector sizes. If you call
303    * reinit() of one of the blocks, then subsequent actions of this object may
304    * yield unpredictable results since they may be routed to the wrong block.
305    */
306   template <typename Number2>
307   void
308   reinit(const BlockVector<Number2> &V,
309          const bool                  omit_zeroing_entries = false);
310 
311   /**
312    * Multiply each element of this vector by the corresponding element of
313    * <tt>v</tt>.
314    */
315   template <class BlockVector2>
316   void
317   scale(const BlockVector2 &v);
318 
319   /**
320    * Swap the contents of this vector and the other vector <tt>v</tt>. One
321    * could do this operation with a temporary variable and copying over the
322    * data elements, but this function is significantly more efficient since it
323    * only swaps the pointers to the data of the two vectors and therefore does
324    * not need to allocate temporary storage and move data around.
325    *
326    * This function is analogous to the swap() function of all C++ standard
327    * containers. Also, there is a global function swap(u,v) that simply calls
328    * <tt>u.swap(v)</tt>, again in analogy to standard functions.
329    */
330   void
331   swap(BlockVector<Number> &v);
332 
333   /**
334    * Print to a stream.
335    */
336   void
337   print(std::ostream &     out,
338         const unsigned int precision  = 3,
339         const bool         scientific = true,
340         const bool         across     = true) const;
341 
342   /**
343    * Write the vector en bloc to a stream. This is done in a binary mode, so
344    * the output is neither readable by humans nor (probably) by other
345    * computers using a different operating system or number format.
346    */
347   void
348   block_write(std::ostream &out) const;
349 
350   /**
351    * Read a vector en block from a file. This is done using the inverse
352    * operations to the above function, so it is reasonably fast because the
353    * bitstream is not interpreted.
354    *
355    * The vector is resized if necessary.
356    *
357    * A primitive form of error checking is performed which will recognize the
358    * bluntest attempts to interpret some data as a vector stored bitwise to a
359    * file, but not more.
360    */
361   void
362   block_read(std::istream &in);
363 
364   /**
365    * @addtogroup Exceptions
366    * @{
367    */
368 
369   /**
370    * Exception
371    */
372   DeclException0(ExcIteratorRangeDoesNotMatchVectorSize);
373   //@}
374 };
375 
376 /*@}*/
377 
378 #ifndef DOXYGEN
379 /*----------------------- Inline functions ----------------------------------*/
380 
381 
382 
383 template <typename Number>
384 template <typename InputIterator>
BlockVector(const std::vector<size_type> & block_sizes,const InputIterator first,const InputIterator end)385 BlockVector<Number>::BlockVector(const std::vector<size_type> &block_sizes,
386                                  const InputIterator           first,
387                                  const InputIterator           end)
388 {
389   // first set sizes of blocks, but
390   // don't initialize them as we will
391   // copy elements soon
392   (void)end;
393   reinit(block_sizes, true);
394   InputIterator start = first;
395   for (size_type b = 0; b < block_sizes.size(); ++b)
396     {
397       InputIterator end = start;
398       std::advance(end, static_cast<signed int>(block_sizes[b]));
399       std::copy(start, end, this->block(b).begin());
400       start = end;
401     };
402   Assert(start == end, ExcIteratorRangeDoesNotMatchVectorSize());
403 }
404 
405 
406 
407 template <typename Number>
408 inline BlockVector<Number> &
409 BlockVector<Number>::operator=(const value_type s)
410 {
411   AssertIsFinite(s);
412 
413   BaseClass::operator=(s);
414   return *this;
415 }
416 
417 
418 
419 template <typename Number>
420 inline BlockVector<Number> &
421 BlockVector<Number>::operator=(const BlockVector<Number> &v)
422 {
423   reinit(v, true);
424   BaseClass::operator=(v);
425   return *this;
426 }
427 
428 
429 
430 template <typename Number>
431 inline BlockVector<Number> &
432 BlockVector<Number>::operator=(const Vector<Number> &v)
433 {
434   BaseClass::operator=(v);
435   return *this;
436 }
437 
438 
439 
440 template <typename Number>
441 template <typename Number2>
442 inline BlockVector<Number> &
443 BlockVector<Number>::operator=(const BlockVector<Number2> &v)
444 {
445   reinit(v, true);
446   BaseClass::operator=(v);
447   return *this;
448 }
449 
450 template <typename Number>
451 inline void
compress(::dealii::VectorOperation::values operation)452 BlockVector<Number>::compress(::dealii::VectorOperation::values operation)
453 {
454   for (size_type i = 0; i < this->n_blocks(); ++i)
455     this->components[i].compress(operation);
456 }
457 
458 
459 
460 template <typename Number>
461 inline bool
has_ghost_elements()462 BlockVector<Number>::has_ghost_elements() const
463 {
464   return false;
465 }
466 
467 
468 
469 template <typename Number>
470 template <class BlockVector2>
471 void
scale(const BlockVector2 & v)472 BlockVector<Number>::scale(const BlockVector2 &v)
473 {
474   BaseClass::scale(v);
475 }
476 
477 #endif // DOXYGEN
478 
479 
480 /**
481  * Global function which overloads the default implementation of the C++
482  * standard library which uses a temporary object. The function simply
483  * exchanges the data of the two vectors.
484  *
485  * @relatesalso BlockVector
486  */
487 template <typename Number>
488 inline void
swap(BlockVector<Number> & u,BlockVector<Number> & v)489 swap(BlockVector<Number> &u, BlockVector<Number> &v)
490 {
491   u.swap(v);
492 }
493 
494 
495 namespace internal
496 {
497   namespace LinearOperatorImplementation
498   {
499     template <typename>
500     class ReinitHelper;
501 
502     /**
503      * A helper class used internally in linear_operator.h. Specialization for
504      * BlockVector<number>.
505      */
506     template <typename number>
507     class ReinitHelper<BlockVector<number>>
508     {
509     public:
510       template <typename Matrix>
511       static void
reinit_range_vector(const Matrix & matrix,BlockVector<number> & v,bool omit_zeroing_entries)512       reinit_range_vector(const Matrix &       matrix,
513                           BlockVector<number> &v,
514                           bool                 omit_zeroing_entries)
515       {
516         v.reinit(matrix.get_row_indices(), omit_zeroing_entries);
517       }
518 
519       template <typename Matrix>
520       static void
reinit_domain_vector(const Matrix & matrix,BlockVector<number> & v,bool omit_zeroing_entries)521       reinit_domain_vector(const Matrix &       matrix,
522                            BlockVector<number> &v,
523                            bool                 omit_zeroing_entries)
524       {
525         v.reinit(matrix.get_column_indices(), omit_zeroing_entries);
526       }
527     };
528 
529   } // namespace LinearOperatorImplementation
530 } /* namespace internal */
531 
532 
533 /**
534  * Declare dealii::BlockVector as serial vector.
535  */
536 template <typename Number>
537 struct is_serial_vector<BlockVector<Number>> : std::true_type
538 {};
539 
540 DEAL_II_NAMESPACE_CLOSE
541 
542 #endif
543