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_parallel_block_vector_templates_h
17 #define dealii_parallel_block_vector_templates_h
18 
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/lac/la_parallel_block_vector.h>
23 #include <deal.II/lac/lapack_support.h>
24 #include <deal.II/lac/petsc_block_vector.h>
25 #include <deal.II/lac/read_write_vector.h>
26 #include <deal.II/lac/trilinos_parallel_block_vector.h>
27 #include <deal.II/lac/vector.h>
28 
29 
30 DEAL_II_NAMESPACE_OPEN
31 
32 // Forward type declaration to have special treatment of
33 // LAPACKFullMatrix<number>
34 // in multivector_inner_product()
35 #ifndef DOXYGEN
36 template <typename Number>
37 class LAPACKFullMatrix;
38 #endif
39 
40 namespace LinearAlgebra
41 {
42   namespace distributed
43   {
44     template <typename Number>
BlockVector(const size_type n_blocks,const size_type block_size)45     BlockVector<Number>::BlockVector(const size_type n_blocks,
46                                      const size_type block_size)
47     {
48       reinit(n_blocks, block_size);
49     }
50 
51 
52 
53     template <typename Number>
BlockVector(const std::vector<size_type> & n)54     BlockVector<Number>::BlockVector(const std::vector<size_type> &n)
55     {
56       reinit(n, false);
57     }
58 
59 
60     template <typename Number>
BlockVector(const std::vector<IndexSet> & local_ranges,const std::vector<IndexSet> & ghost_indices,const MPI_Comm communicator)61     BlockVector<Number>::BlockVector(const std::vector<IndexSet> &local_ranges,
62                                      const std::vector<IndexSet> &ghost_indices,
63                                      const MPI_Comm               communicator)
64     {
65       std::vector<size_type> sizes(local_ranges.size());
66       for (unsigned int i = 0; i < local_ranges.size(); ++i)
67         sizes[i] = local_ranges[i].size();
68 
69       this->block_indices.reinit(sizes);
70       this->components.resize(this->n_blocks());
71 
72       for (unsigned int i = 0; i < this->n_blocks(); ++i)
73         this->block(i).reinit(local_ranges[i], ghost_indices[i], communicator);
74     }
75 
76 
77     template <typename Number>
BlockVector(const std::vector<IndexSet> & local_ranges,const MPI_Comm communicator)78     BlockVector<Number>::BlockVector(const std::vector<IndexSet> &local_ranges,
79                                      const MPI_Comm               communicator)
80     {
81       std::vector<size_type> sizes(local_ranges.size());
82       for (unsigned int i = 0; i < local_ranges.size(); ++i)
83         sizes[i] = local_ranges[i].size();
84 
85       this->block_indices.reinit(sizes);
86       this->components.resize(this->n_blocks());
87 
88       for (unsigned int i = 0; i < this->n_blocks(); ++i)
89         this->block(i).reinit(local_ranges[i], communicator);
90     }
91 
92 
93 
94     template <typename Number>
BlockVector(const BlockVector<Number> & v)95     BlockVector<Number>::BlockVector(const BlockVector<Number> &v)
96       : BlockVectorBase<Vector<Number>>()
97     {
98       this->components.resize(v.n_blocks());
99       this->block_indices = v.block_indices;
100 
101       for (size_type i = 0; i < this->n_blocks(); ++i)
102         this->components[i] = v.components[i];
103     }
104 
105 
106 
107     template <typename Number>
108     template <typename OtherNumber>
BlockVector(const BlockVector<OtherNumber> & v)109     BlockVector<Number>::BlockVector(const BlockVector<OtherNumber> &v)
110     {
111       reinit(v, true);
112       *this = v;
113     }
114 
115 
116 
117     template <typename Number>
118     void
reinit(const size_type n_bl,const size_type bl_sz,const bool omit_zeroing_entries)119     BlockVector<Number>::reinit(const size_type n_bl,
120                                 const size_type bl_sz,
121                                 const bool      omit_zeroing_entries)
122     {
123       std::vector<size_type> n(n_bl, bl_sz);
124       reinit(n, omit_zeroing_entries);
125     }
126 
127 
128     template <typename Number>
129     void
reinit(const std::vector<size_type> & n,const bool omit_zeroing_entries)130     BlockVector<Number>::reinit(const std::vector<size_type> &n,
131                                 const bool omit_zeroing_entries)
132     {
133       this->block_indices.reinit(n);
134       if (this->components.size() != this->n_blocks())
135         this->components.resize(this->n_blocks());
136 
137       for (size_type i = 0; i < this->n_blocks(); ++i)
138         this->components[i].reinit(n[i], omit_zeroing_entries);
139     }
140 
141 
142 
143     template <typename Number>
144     template <typename Number2>
145     void
reinit(const BlockVector<Number2> & v,const bool omit_zeroing_entries)146     BlockVector<Number>::reinit(const BlockVector<Number2> &v,
147                                 const bool omit_zeroing_entries)
148     {
149       this->block_indices = v.get_block_indices();
150       if (this->components.size() != this->n_blocks())
151         this->components.resize(this->n_blocks());
152 
153       for (unsigned int i = 0; i < this->n_blocks(); ++i)
154         this->block(i).reinit(v.block(i), omit_zeroing_entries);
155     }
156 
157 
158 
159     template <typename Number>
160     BlockVector<Number> &
161     BlockVector<Number>::operator=(const value_type s)
162     {
163       AssertIsFinite(s);
164 
165       BaseClass::operator=(s);
166       return *this;
167     }
168 
169 
170 
171     template <typename Number>
172     BlockVector<Number> &
173     BlockVector<Number>::operator=(const BlockVector &v)
174     {
175       // we only allow assignment to vectors with the same number of blocks
176       // or to an empty BlockVector
177       Assert(this->n_blocks() == 0 || this->n_blocks() == v.n_blocks(),
178              ExcDimensionMismatch(this->n_blocks(), v.n_blocks()));
179 
180       if (this->n_blocks() != v.n_blocks())
181         reinit(v.n_blocks(), true);
182 
183       for (size_type i = 0; i < this->n_blocks(); ++i)
184         this->components[i] = v.block(i);
185 
186       this->collect_sizes();
187       return *this;
188     }
189 
190 
191 
192     template <typename Number>
193     BlockVector<Number> &
194     BlockVector<Number>::operator=(const Vector<Number> &v)
195     {
196       BaseClass::operator=(v);
197       return *this;
198     }
199 
200 
201 
202     template <typename Number>
203     template <typename Number2>
204     BlockVector<Number> &
205     BlockVector<Number>::operator=(const BlockVector<Number2> &v)
206     {
207       reinit(v, true);
208       BaseClass::operator=(v);
209       return *this;
210     }
211 
212 
213 
214 #ifdef DEAL_II_WITH_PETSC
215 
216     namespace petsc_helpers
217     {
218       template <typename PETSC_Number, typename Number>
219       void
copy_petsc_vector(const PETSC_Number * petsc_start_ptr,const PETSC_Number * petsc_end_ptr,Number * ptr)220       copy_petsc_vector(const PETSC_Number *petsc_start_ptr,
221                         const PETSC_Number *petsc_end_ptr,
222                         Number *            ptr)
223       {
224         std::copy(petsc_start_ptr, petsc_end_ptr, ptr);
225       }
226 
227       template <typename PETSC_Number, typename Number>
228       void
copy_petsc_vector(const std::complex<PETSC_Number> * petsc_start_ptr,const std::complex<PETSC_Number> * petsc_end_ptr,std::complex<Number> * ptr)229       copy_petsc_vector(const std::complex<PETSC_Number> *petsc_start_ptr,
230                         const std::complex<PETSC_Number> *petsc_end_ptr,
231                         std::complex<Number> *            ptr)
232       {
233         std::copy(petsc_start_ptr, petsc_end_ptr, ptr);
234       }
235 
236       template <typename PETSC_Number, typename Number>
237       void
copy_petsc_vector(const std::complex<PETSC_Number> *,const std::complex<PETSC_Number> *,Number *)238       copy_petsc_vector(const std::complex<PETSC_Number> * /*petsc_start_ptr*/,
239                         const std::complex<PETSC_Number> * /*petsc_end_ptr*/,
240                         Number * /*ptr*/)
241       {
242         AssertThrow(false, ExcMessage("Tried to copy complex -> real"));
243       }
244     } // namespace petsc_helpers
245 
246 
247 
248     template <typename Number>
249     BlockVector<Number> &
250     BlockVector<Number>::
251     operator=(const PETScWrappers::MPI::BlockVector &petsc_vec)
252     {
253       AssertDimension(this->n_blocks(), petsc_vec.n_blocks());
254       for (unsigned int i = 0; i < this->n_blocks(); ++i)
255         {
256           // We would like to use the same compact infrastructure as for the
257           // Trilinos vector below, but the interface through ReadWriteVector
258           // does not support overlapping (ghosted) PETSc vectors, which we need
259           // for backward compatibility.
260 
261           Assert(petsc_vec.block(i).locally_owned_elements() ==
262                    this->block(i).locally_owned_elements(),
263                  StandardExceptions::ExcInvalidState());
264 
265           // get a representation of the vector and copy it
266           PetscScalar *  start_ptr;
267           PetscErrorCode ierr =
268             VecGetArray(static_cast<const Vec &>(petsc_vec.block(i)),
269                         &start_ptr);
270           AssertThrow(ierr == 0, ExcPETScError(ierr));
271 
272           const size_type vec_size = this->block(i).local_size();
273           petsc_helpers::copy_petsc_vector(start_ptr,
274                                            start_ptr + vec_size,
275                                            this->block(i).begin());
276 
277           // restore the representation of the vector
278           ierr = VecRestoreArray(static_cast<const Vec &>(petsc_vec.block(i)),
279                                  &start_ptr);
280           AssertThrow(ierr == 0, ExcPETScError(ierr));
281 
282           // spread ghost values between processes?
283           if (this->block(i).vector_is_ghosted ||
284               petsc_vec.block(i).has_ghost_elements())
285             this->block(i).update_ghost_values();
286         }
287 
288       return *this;
289     }
290 
291 #endif
292 
293 
294 
295 #ifdef DEAL_II_WITH_TRILINOS
296 
297     template <typename Number>
298     BlockVector<Number> &
299     BlockVector<Number>::
300     operator=(const TrilinosWrappers::MPI::BlockVector &trilinos_vec)
301     {
302       AssertDimension(this->n_blocks(), trilinos_vec.n_blocks());
303       for (unsigned int i = 0; i < this->n_blocks(); ++i)
304         {
305           const auto &partitioner  = this->block(i).get_partitioner();
306           IndexSet    combined_set = partitioner->locally_owned_range();
307           combined_set.add_indices(partitioner->ghost_indices());
308           ReadWriteVector<Number> rw_vector(combined_set);
309           rw_vector.import(trilinos_vec.block(i), VectorOperation::insert);
310           this->block(i).import(rw_vector, VectorOperation::insert);
311 
312           if (this->block(i).has_ghost_elements() ||
313               trilinos_vec.block(i).has_ghost_elements())
314             this->block(i).update_ghost_values();
315         }
316 
317       return *this;
318     }
319 
320 #endif
321 
322 
323 
324     template <typename Number>
325     void
compress(::dealii::VectorOperation::values operation)326     BlockVector<Number>::compress(::dealii::VectorOperation::values operation)
327     {
328       const unsigned int n_chunks =
329         (this->n_blocks() + communication_block_size - 1) /
330         communication_block_size;
331       for (unsigned int c = 0; c < n_chunks; ++c)
332         {
333           const unsigned int start = c * communication_block_size;
334           const unsigned int end =
335             std::min(start + communication_block_size, this->n_blocks());
336 
337           // start all requests for all blocks before finishing the transfers as
338           // this saves repeated synchronizations. In order to avoid conflict
339           // with possible other ongoing communication requests (from
340           // LA::distributed::Vector that supports unfinished requests), add
341           // 100 to the communication tag (the first 100 can be used by normal
342           // vectors).
343           for (unsigned int block = start; block < end; ++block)
344             this->block(block).compress_start(block - start + 100, operation);
345           for (unsigned int block = start; block < end; ++block)
346             this->block(block).compress_finish(operation);
347         }
348     }
349 
350 
351 
352     template <typename Number>
353     void
update_ghost_values()354     BlockVector<Number>::update_ghost_values() const
355     {
356       const unsigned int n_chunks =
357         (this->n_blocks() + communication_block_size - 1) /
358         communication_block_size;
359       for (unsigned int c = 0; c < n_chunks; ++c)
360         {
361           const unsigned int start = c * communication_block_size;
362           const unsigned int end =
363             std::min(start + communication_block_size, this->n_blocks());
364 
365           // In order to avoid conflict with possible other ongoing
366           // communication requests (from LA::distributed::Vector that supports
367           // unfinished requests), add 100 to the communication tag (the first
368           // 100 can be used by normal vectors)
369           for (unsigned int block = start; block < end; ++block)
370             this->block(block).update_ghost_values_start(block - start + 100);
371           for (unsigned int block = start; block < end; ++block)
372             this->block(block).update_ghost_values_finish();
373         }
374     }
375 
376 
377 
378     template <typename Number>
379     void
zero_out_ghosts()380     BlockVector<Number>::zero_out_ghosts() const
381     {
382       for (unsigned int block = 0; block < this->n_blocks(); ++block)
383         this->block(block).zero_out_ghosts();
384     }
385 
386 
387 
388     template <typename Number>
389     bool
has_ghost_elements()390     BlockVector<Number>::has_ghost_elements() const
391     {
392       bool has_ghost_elements = false;
393       for (unsigned int block = 0; block < this->n_blocks(); ++block)
394         if (this->block(block).has_ghost_elements() == true)
395           has_ghost_elements = true;
396       return has_ghost_elements;
397     }
398 
399 
400 
401     template <typename Number>
402     void
reinit(const VectorSpaceVector<Number> & V,const bool omit_zeroing_entries)403     BlockVector<Number>::reinit(const VectorSpaceVector<Number> &V,
404                                 const bool omit_zeroing_entries)
405     {
406       Assert(dynamic_cast<const BlockVector<Number> *>(&V) != nullptr,
407              ExcVectorTypeNotCompatible());
408       const BlockVector<Number> &down_V =
409         dynamic_cast<const BlockVector<Number> &>(V);
410       reinit(down_V, omit_zeroing_entries);
411     }
412 
413 
414     template <typename Number>
415     BlockVector<Number> &
416     BlockVector<Number>::operator*=(const Number factor)
417     {
418       for (unsigned int block = 0; block < this->n_blocks(); ++block)
419         this->block(block) *= factor;
420       return *this;
421     }
422 
423 
424 
425     template <typename Number>
426     BlockVector<Number> &
427     BlockVector<Number>::operator/=(const Number factor)
428     {
429       operator*=(static_cast<Number>(1.) / factor);
430       return *this;
431     }
432 
433 
434 
435     template <typename Number>
436     void
scale(const VectorSpaceVector<Number> & vv)437     BlockVector<Number>::scale(const VectorSpaceVector<Number> &vv)
438     {
439       // Downcast. Throws an exception if invalid.
440       Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr,
441              ExcVectorTypeNotCompatible());
442       const BlockVector<Number> &v =
443         dynamic_cast<const BlockVector<Number> &>(vv);
444       AssertDimension(this->n_blocks(), v.n_blocks());
445       for (unsigned int block = 0; block < this->n_blocks(); ++block)
446         this->block(block).scale(v.block(block));
447     }
448 
449 
450 
451     template <typename Number>
452     void
equ(const Number a,const VectorSpaceVector<Number> & vv)453     BlockVector<Number>::equ(const Number                     a,
454                              const VectorSpaceVector<Number> &vv)
455     {
456       // Downcast. Throws an exception if invalid.
457       Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr,
458              ExcVectorTypeNotCompatible());
459       const BlockVector<Number> &v =
460         dynamic_cast<const BlockVector<Number> &>(vv);
461       AssertDimension(this->n_blocks(), v.n_blocks());
462       for (unsigned int block = 0; block < this->n_blocks(); ++block)
463         this->block(block).equ(a, v.block(block));
464     }
465 
466 
467 
468     template <typename Number>
469     BlockVector<Number> &
470     BlockVector<Number>::operator+=(const VectorSpaceVector<Number> &vv)
471     {
472       // Downcast. Throws an exception if invalid.
473       Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr,
474              ExcVectorTypeNotCompatible());
475       const BlockVector<Number> &v =
476         dynamic_cast<const BlockVector<Number> &>(vv);
477       AssertDimension(this->n_blocks(), v.n_blocks());
478       for (unsigned int block = 0; block < this->n_blocks(); ++block)
479         this->block(block) += v.block(block);
480 
481       return *this;
482     }
483 
484 
485 
486     template <typename Number>
487     BlockVector<Number> &
488     BlockVector<Number>::operator-=(const VectorSpaceVector<Number> &vv)
489     {
490       // Downcast. Throws an exception if invalid.
491       Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr,
492              ExcVectorTypeNotCompatible());
493       const BlockVector<Number> &v =
494         dynamic_cast<const BlockVector<Number> &>(vv);
495       AssertDimension(this->n_blocks(), v.n_blocks());
496       for (unsigned int block = 0; block < this->n_blocks(); ++block)
497         this->block(block) -= v.block(block);
498 
499       return *this;
500     }
501 
502 
503 
504     template <typename Number>
505     void
add(const Number a)506     BlockVector<Number>::add(const Number a)
507     {
508       for (unsigned int block = 0; block < this->n_blocks(); ++block)
509         this->block(block).add(a);
510     }
511 
512 
513 
514     template <typename Number>
515     void
add(const Number a,const VectorSpaceVector<Number> & vv)516     BlockVector<Number>::add(const Number                     a,
517                              const VectorSpaceVector<Number> &vv)
518     {
519       // Downcast. Throws an exception if invalid.
520       Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr,
521              ExcVectorTypeNotCompatible());
522       const BlockVector<Number> &v =
523         dynamic_cast<const BlockVector<Number> &>(vv);
524       AssertDimension(this->n_blocks(), v.n_blocks());
525       for (unsigned int block = 0; block < this->n_blocks(); ++block)
526         this->block(block).add(a, v.block(block));
527     }
528 
529 
530 
531     template <typename Number>
532     void
add(const Number a,const VectorSpaceVector<Number> & vv,const Number b,const VectorSpaceVector<Number> & ww)533     BlockVector<Number>::add(const Number                     a,
534                              const VectorSpaceVector<Number> &vv,
535                              const Number                     b,
536                              const VectorSpaceVector<Number> &ww)
537     {
538       // Downcast. Throws an exception if invalid.
539       Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr,
540              ExcVectorTypeNotCompatible());
541       const BlockVector<Number> &v =
542         dynamic_cast<const BlockVector<Number> &>(vv);
543       AssertDimension(this->n_blocks(), v.n_blocks());
544       Assert(dynamic_cast<const BlockVector<Number> *>(&ww) != nullptr,
545              ExcVectorTypeNotCompatible());
546       const BlockVector<Number> &w =
547         dynamic_cast<const BlockVector<Number> &>(ww);
548       AssertDimension(this->n_blocks(), v.n_blocks());
549 
550       for (unsigned int block = 0; block < this->n_blocks(); ++block)
551         this->block(block).add(a, v.block(block), b, w.block(block));
552     }
553 
554 
555 
556     template <typename Number>
557     void
sadd(const Number x,const Number a,const VectorSpaceVector<Number> & vv)558     BlockVector<Number>::sadd(const Number                     x,
559                               const Number                     a,
560                               const VectorSpaceVector<Number> &vv)
561     {
562       // Downcast. Throws an exception if invalid.
563       Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr,
564              ExcVectorTypeNotCompatible());
565       const BlockVector<Number> &v =
566         dynamic_cast<const BlockVector<Number> &>(vv);
567       AssertDimension(this->n_blocks(), v.n_blocks());
568       for (unsigned int block = 0; block < this->n_blocks(); ++block)
569         this->block(block).sadd(x, a, v.block(block));
570     }
571 
572 
573 
574     template <typename Number>
575     void
sadd(const Number x,const BlockVector<Number> & v)576     BlockVector<Number>::sadd(const Number x, const BlockVector<Number> &v)
577     {
578       AssertDimension(this->n_blocks(), v.n_blocks());
579       for (unsigned int block = 0; block < this->n_blocks(); ++block)
580         this->block(block).sadd(x, v.block(block));
581     }
582 
583 
584 
585     template <typename Number>
586     template <typename OtherNumber>
587     void
add(const std::vector<size_type> & indices,const::dealii::Vector<OtherNumber> & values)588     BlockVector<Number>::add(const std::vector<size_type> &       indices,
589                              const ::dealii::Vector<OtherNumber> &values)
590     {
591       for (size_type i = 0; i < indices.size(); ++i)
592         (*this)(indices[i]) += values[i];
593     }
594 
595 
596 
597     template <typename Number>
598     void
add(const std::vector<size_type> & indices,const std::vector<Number> & values)599     BlockVector<Number>::add(const std::vector<size_type> &indices,
600                              const std::vector<Number> &   values)
601     {
602       for (size_type i = 0; i < indices.size(); ++i)
603         (*this)(indices[i]) += values[i];
604     }
605 
606 
607 
608     template <typename Number>
609     bool
all_zero()610     BlockVector<Number>::all_zero() const
611     {
612       Assert(this->n_blocks() > 0, ExcEmptyObject());
613 
614       // use int instead of bool. in order to make global reduction operations
615       // work also when MPI_Init was not called, only call MPI_Allreduce
616       // commands when there is more than one processor (note that reinit()
617       // functions handle this case correctly through the job_supports_mpi()
618       // query). this is the same in all the functions below
619       int local_result = -1;
620       for (unsigned int i = 0; i < this->n_blocks(); ++i)
621         local_result =
622           std::max(local_result,
623                    (this->block(i).linfty_norm_local() == 0) ? -1 : 0);
624 
625       if (this->block(0).partitioner->n_mpi_processes() > 1)
626         return -Utilities::MPI::max(
627           local_result, this->block(0).partitioner->get_mpi_communicator());
628       else
629         return local_result;
630     }
631 
632 
633 
634     template <typename Number>
635     Number BlockVector<Number>::
636            operator*(const VectorSpaceVector<Number> &vv) const
637     {
638       Assert(this->n_blocks() > 0, ExcEmptyObject());
639 
640       // Downcast. Throws an exception if invalid.
641       Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr,
642              ExcVectorTypeNotCompatible());
643       const BlockVector<Number> &v =
644         dynamic_cast<const BlockVector<Number> &>(vv);
645       AssertDimension(this->n_blocks(), v.n_blocks());
646 
647       Number local_result = Number();
648       for (unsigned int i = 0; i < this->n_blocks(); ++i)
649         local_result += this->block(i).inner_product_local(v.block(i));
650 
651       if (this->block(0).partitioner->n_mpi_processes() > 1)
652         return Utilities::MPI::sum(
653           local_result, this->block(0).partitioner->get_mpi_communicator());
654       else
655         return local_result;
656     }
657 
658 
659 
660     template <typename Number>
661     inline Number
mean_value()662     BlockVector<Number>::mean_value() const
663     {
664       Assert(this->n_blocks() > 0, ExcEmptyObject());
665 
666       Number local_result = Number();
667       for (unsigned int i = 0; i < this->n_blocks(); ++i)
668         local_result +=
669           this->block(i).mean_value_local() *
670           static_cast<real_type>(this->block(i).partitioner->local_size());
671 
672       if (this->block(0).partitioner->n_mpi_processes() > 1)
673         return Utilities::MPI::sum(
674                  local_result,
675                  this->block(0).partitioner->get_mpi_communicator()) /
676                static_cast<real_type>(this->size());
677       else
678         return local_result / static_cast<real_type>(this->size());
679     }
680 
681 
682 
683     template <typename Number>
684     inline typename BlockVector<Number>::real_type
l1_norm()685     BlockVector<Number>::l1_norm() const
686     {
687       Assert(this->n_blocks() > 0, ExcEmptyObject());
688 
689       real_type local_result = real_type();
690       for (unsigned int i = 0; i < this->n_blocks(); ++i)
691         local_result += this->block(i).l1_norm_local();
692 
693       if (this->block(0).partitioner->n_mpi_processes() > 1)
694         return Utilities::MPI::sum(
695           local_result, this->block(0).partitioner->get_mpi_communicator());
696       else
697         return local_result;
698     }
699 
700 
701 
702     template <typename Number>
703     inline typename BlockVector<Number>::real_type
norm_sqr()704     BlockVector<Number>::norm_sqr() const
705     {
706       Assert(this->n_blocks() > 0, ExcEmptyObject());
707 
708       real_type local_result = real_type();
709       for (unsigned int i = 0; i < this->n_blocks(); ++i)
710         local_result += this->block(i).norm_sqr_local();
711 
712       if (this->block(0).partitioner->n_mpi_processes() > 1)
713         return Utilities::MPI::sum(
714           local_result, this->block(0).partitioner->get_mpi_communicator());
715       else
716         return local_result;
717     }
718 
719 
720 
721     template <typename Number>
722     inline typename BlockVector<Number>::real_type
l2_norm()723     BlockVector<Number>::l2_norm() const
724     {
725       return std::sqrt(norm_sqr());
726     }
727 
728 
729 
730     template <typename Number>
731     inline typename BlockVector<Number>::real_type
lp_norm(const real_type p)732     BlockVector<Number>::lp_norm(const real_type p) const
733     {
734       Assert(this->n_blocks() > 0, ExcEmptyObject());
735 
736       real_type local_result = real_type();
737       for (unsigned int i = 0; i < this->n_blocks(); ++i)
738         local_result += std::pow(this->block(i).lp_norm_local(p), p);
739 
740       if (this->block(0).partitioner->n_mpi_processes() > 1)
741         return std::pow(Utilities::MPI::sum(
742                           local_result,
743                           this->block(0).partitioner->get_mpi_communicator()),
744                         static_cast<real_type>(1.0 / p));
745       else
746         return std::pow(local_result, static_cast<real_type>(1.0 / p));
747     }
748 
749 
750 
751     template <typename Number>
752     inline typename BlockVector<Number>::real_type
linfty_norm()753     BlockVector<Number>::linfty_norm() const
754     {
755       Assert(this->n_blocks() > 0, ExcEmptyObject());
756 
757       real_type local_result = real_type();
758       for (unsigned int i = 0; i < this->n_blocks(); ++i)
759         local_result =
760           std::max(local_result, this->block(i).linfty_norm_local());
761 
762       if (this->block(0).partitioner->n_mpi_processes() > 1)
763         return Utilities::MPI::max(
764           local_result, this->block(0).partitioner->get_mpi_communicator());
765       else
766         return local_result;
767     }
768 
769 
770 
771     template <typename Number>
772     inline Number
add_and_dot(const Number a,const VectorSpaceVector<Number> & vv,const VectorSpaceVector<Number> & ww)773     BlockVector<Number>::add_and_dot(const Number                     a,
774                                      const VectorSpaceVector<Number> &vv,
775                                      const VectorSpaceVector<Number> &ww)
776     {
777       // Downcast. Throws an exception if invalid.
778       Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr,
779              ExcVectorTypeNotCompatible());
780       const BlockVector<Number> &v =
781         dynamic_cast<const BlockVector<Number> &>(vv);
782       AssertDimension(this->n_blocks(), v.n_blocks());
783 
784       // Downcast. Throws an exception if invalid.
785       Assert(dynamic_cast<const BlockVector<Number> *>(&ww) != nullptr,
786              ExcVectorTypeNotCompatible());
787       const BlockVector<Number> &w =
788         dynamic_cast<const BlockVector<Number> &>(ww);
789       AssertDimension(this->n_blocks(), w.n_blocks());
790 
791       Number local_result = Number();
792       for (unsigned int i = 0; i < this->n_blocks(); ++i)
793         local_result +=
794           this->block(i).add_and_dot_local(a, v.block(i), w.block(i));
795 
796       if (this->block(0).partitioner->n_mpi_processes() > 1)
797         return Utilities::MPI::sum(
798           local_result, this->block(0).partitioner->get_mpi_communicator());
799       else
800         return local_result;
801     }
802 
803 
804 
805     template <typename Number>
806     inline void
swap(BlockVector<Number> & v)807     BlockVector<Number>::swap(BlockVector<Number> &v)
808     {
809       Assert(this->n_blocks() == v.n_blocks(),
810              ExcDimensionMismatch(this->n_blocks(), v.n_blocks()));
811 
812       for (size_type i = 0; i < this->n_blocks(); ++i)
813         dealii::swap(this->components[i], v.components[i]);
814       dealii::swap(this->block_indices, v.block_indices);
815     }
816 
817 
818 
819     template <typename Number>
820     typename BlockVector<Number>::size_type
size()821     BlockVector<Number>::size() const
822     {
823       return this->block_indices.total_size();
824     }
825 
826 
827 
828     template <typename Number>
829     inline void
import(const LinearAlgebra::ReadWriteVector<Number> &,VectorOperation::values,std::shared_ptr<const CommunicationPatternBase>)830     BlockVector<Number>::import(const LinearAlgebra::ReadWriteVector<Number> &,
831                                 VectorOperation::values,
832                                 std::shared_ptr<const CommunicationPatternBase>)
833     {
834       AssertThrow(false, ExcNotImplemented());
835     }
836 
837 
838 
839     template <typename Number>
840     IndexSet
locally_owned_elements()841     BlockVector<Number>::locally_owned_elements() const
842     {
843       IndexSet is(size());
844 
845       // copy index sets from blocks into the global one, shifted by the
846       // appropriate amount for each block
847       for (unsigned int b = 0; b < this->n_blocks(); ++b)
848         {
849           IndexSet x = this->block(b).locally_owned_elements();
850           is.add_indices(x, this->block_indices.block_start(b));
851         }
852 
853       is.compress();
854 
855       return is;
856     }
857 
858     template <typename Number>
859     void
print(std::ostream & out,const unsigned int precision,const bool scientific,const bool across)860     BlockVector<Number>::print(std::ostream &     out,
861                                const unsigned int precision,
862                                const bool         scientific,
863                                const bool         across) const
864     {
865       for (unsigned int b = 0; b < this->n_blocks(); ++b)
866         this->block(b).print(out, precision, scientific, across);
867     }
868 
869 
870 
871     template <typename Number>
872     std::size_t
memory_consumption()873     BlockVector<Number>::memory_consumption() const
874     {
875       return (MemoryConsumption::memory_consumption(this->block_indices) +
876               MemoryConsumption::memory_consumption(this->components));
877     }
878 
879 
880 
881     namespace internal
882     {
883       template <typename FullMatrixType>
884       inline void
set_symmetric(FullMatrixType &,const bool)885       set_symmetric(FullMatrixType &, const bool)
886       {}
887 
888       template <typename NumberType>
889       inline void
set_symmetric(LAPACKFullMatrix<NumberType> & matrix,const bool symmetric)890       set_symmetric(LAPACKFullMatrix<NumberType> &matrix, const bool symmetric)
891       {
892         if (symmetric)
893           matrix.set_property(LAPACKSupport::symmetric);
894         else
895           matrix.set_property(LAPACKSupport::general);
896       }
897     } // namespace internal
898 
899 
900 
901     template <typename Number>
902     template <typename FullMatrixType>
903     void
multivector_inner_product(FullMatrixType & matrix,const BlockVector<Number> & V,const bool symmetric)904     BlockVector<Number>::multivector_inner_product(FullMatrixType &matrix,
905                                                    const BlockVector<Number> &V,
906                                                    const bool symmetric) const
907     {
908       const unsigned int m = this->n_blocks();
909       const unsigned int n = V.n_blocks();
910 
911       // in case one vector is empty and the second one is not, the
912       // FullMatrix resized to (m,n) will have 0 both in m() and n()
913       // which is how TableBase<N,T>::reinit() works as of deal.ii@8.5.0.
914       // Since in this case there is nothing to do anyway -- return immediately.
915       if (n == 0 || m == 0)
916         return;
917 
918       Assert(matrix.m() == m, ExcDimensionMismatch(matrix.m(), m));
919       Assert(matrix.n() == n, ExcDimensionMismatch(matrix.n(), n));
920 
921       // reset the matrix
922       matrix = typename FullMatrixType::value_type(0.0);
923 
924       internal::set_symmetric(matrix, symmetric);
925       if (symmetric)
926         {
927           Assert(m == n, ExcDimensionMismatch(m, n));
928 
929           for (unsigned int i = 0; i < m; i++)
930             for (unsigned int j = i; j < n; j++)
931               matrix(i, j) = this->block(i).inner_product_local(V.block(j));
932 
933           for (unsigned int i = 0; i < m; i++)
934             for (unsigned int j = i + 1; j < n; j++)
935               matrix(j, i) = matrix(i, j);
936         }
937       else
938         {
939           for (unsigned int i = 0; i < m; ++i)
940             for (unsigned int j = 0; j < n; ++j)
941               matrix(i, j) = this->block(i).inner_product_local(V.block(j));
942         }
943 
944       Utilities::MPI::sum(matrix,
945                           this->block(0).get_mpi_communicator(),
946                           matrix);
947     }
948 
949 
950 
951     template <typename Number>
952     template <typename FullMatrixType>
953     Number
multivector_inner_product_with_metric(const FullMatrixType & matrix,const BlockVector<Number> & V,const bool symmetric)954     BlockVector<Number>::multivector_inner_product_with_metric(
955       const FullMatrixType &     matrix,
956       const BlockVector<Number> &V,
957       const bool                 symmetric) const
958     {
959       Number res = Number(0.);
960 
961       const unsigned int m = this->n_blocks();
962       const unsigned int n = V.n_blocks();
963 
964       // in case one vector is empty and the second one is not, the
965       // FullMatrix resized to (m,n) will have 0 both in m() and n()
966       // which is how TableBase<N,T>::reinit() works.
967       // Since in this case there is nothing to do anyway -- return immediately.
968       if (n == 0 || m == 0)
969         return res;
970 
971       Assert(matrix.m() == m, ExcDimensionMismatch(matrix.m(), m));
972       Assert(matrix.n() == n, ExcDimensionMismatch(matrix.n(), n));
973 
974       if (symmetric)
975         {
976           Assert(m == n, ExcDimensionMismatch(m, n));
977 
978           for (unsigned int i = 0; i < m; i++)
979             {
980               res +=
981                 matrix(i, i) * this->block(i).inner_product_local(V.block(i));
982               for (unsigned int j = i + 1; j < n; j++)
983                 res += 2. * matrix(i, j) *
984                        this->block(i).inner_product_local(V.block(j));
985             }
986         }
987       else
988         {
989           for (unsigned int i = 0; i < m; i++)
990             for (unsigned int j = 0; j < n; j++)
991               res +=
992                 matrix(i, j) * this->block(i).inner_product_local(V.block(j));
993         }
994 
995       return Utilities::MPI::sum(res, this->block(0).get_mpi_communicator());
996     }
997 
998 
999 
1000     template <typename Number>
1001     template <typename FullMatrixType>
1002     void
mmult(BlockVector<Number> & V,const FullMatrixType & matrix,const Number s,const Number b)1003     BlockVector<Number>::mmult(BlockVector<Number> & V,
1004                                const FullMatrixType &matrix,
1005                                const Number          s,
1006                                const Number          b) const
1007     {
1008       const unsigned int m = this->n_blocks();
1009       const unsigned int n = V.n_blocks();
1010 
1011       // in case one vector is empty and the second one is not, the
1012       // FullMatrix resized to (m,n) will have 0 both in m() and n()
1013       // which is how TableBase<N,T>::reinit() works.
1014       // Since in this case there is nothing to do anyway -- return immediately.
1015       if (n == 0 || m == 0)
1016         return;
1017 
1018       Assert(matrix.m() == m, ExcDimensionMismatch(matrix.m(), m));
1019       Assert(matrix.n() == n, ExcDimensionMismatch(matrix.n(), n));
1020 
1021       for (unsigned int i = 0; i < n; i++)
1022         {
1023           // below we make this work gracefully for identity-like matrices in
1024           // which case the two loops over j won't do any work as A(j,i)==0
1025           const unsigned int k = std::min(i, m - 1);
1026           V.block(i).sadd_local(s, matrix(k, i) * b, this->block(k));
1027           for (unsigned int j = 0; j < k; j++)
1028             V.block(i).add_local(matrix(j, i) * b, this->block(j));
1029           for (unsigned int j = k + 1; j < m; j++)
1030             V.block(i).add_local(matrix(j, i) * b, this->block(j));
1031         }
1032 
1033       if (V.block(0).vector_is_ghosted)
1034         {
1035           for (unsigned int i = 0; i < n; i++)
1036             Assert(V.block(i).vector_is_ghosted,
1037                    ExcMessage(
1038                      "All blocks should be either in ghosted state or not."));
1039 
1040           V.update_ghost_values();
1041         }
1042     }
1043 
1044 
1045 
1046   } // end of namespace distributed
1047 
1048 } // namespace LinearAlgebra
1049 
1050 DEAL_II_NAMESPACE_CLOSE
1051 
1052 #endif
1053