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