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_relaxation_block_templates_h
17 #define dealii_relaxation_block_templates_h
18 
19 #include <deal.II/base/config.h>
20 
21 #include <deal.II/lac/full_matrix.h>
22 #include <deal.II/lac/relaxation_block.h>
23 #include <deal.II/lac/trilinos_vector.h>
24 #include <deal.II/lac/vector_memory.h>
25 
26 DEAL_II_NAMESPACE_OPEN
27 
28 template <typename MatrixType, typename InverseNumberType, typename VectorType>
29 inline RelaxationBlock<MatrixType, InverseNumberType, VectorType>::
AdditionalData(const double relaxation,const bool invert_diagonal,const bool same_diagonal,const typename PreconditionBlockBase<InverseNumberType>::Inversion inversion,const double threshold,VectorType * temp_ghost_vector)30   AdditionalData::AdditionalData(
31     const double relaxation,
32     const bool   invert_diagonal,
33     const bool   same_diagonal,
34     const typename PreconditionBlockBase<InverseNumberType>::Inversion
35                  inversion,
36     const double threshold,
37     VectorType * temp_ghost_vector)
38   : relaxation(relaxation)
39   , invert_diagonal(invert_diagonal)
40   , same_diagonal(same_diagonal)
41   , inversion(inversion)
42   , threshold(threshold)
43   , temp_ghost_vector(temp_ghost_vector)
44 {}
45 
46 
47 template <typename MatrixType, typename InverseNumberType, typename VectorType>
48 inline std::size_t
49 RelaxationBlock<MatrixType, InverseNumberType, VectorType>::AdditionalData::
memory_consumption()50   memory_consumption() const
51 {
52   return sizeof(*this) + block_list.memory_consumption() - sizeof(block_list) +
53          MemoryConsumption::memory_consumption(order);
54 }
55 
56 
57 template <typename MatrixType, typename InverseNumberType, typename VectorType>
58 inline void
initialize(const MatrixType & M,const AdditionalData & parameters)59 RelaxationBlock<MatrixType, InverseNumberType, VectorType>::initialize(
60   const MatrixType &    M,
61   const AdditionalData &parameters)
62 {
63   Assert(parameters.invert_diagonal, ExcNotImplemented());
64 
65   clear();
66   //  Assert (M.m() == M.n(), ExcNotQuadratic());
67   A               = &M;
68   additional_data = &parameters;
69   this->inversion = parameters.inversion;
70 
71   this->reinit(additional_data->block_list.n_rows(),
72                0,
73                additional_data->same_diagonal,
74                additional_data->inversion);
75 
76   if (additional_data->invert_diagonal)
77     invert_diagblocks();
78 }
79 
80 
81 template <typename MatrixType, typename InverseNumberType, typename VectorType>
82 inline void
clear()83 RelaxationBlock<MatrixType, InverseNumberType, VectorType>::clear()
84 {
85   A               = nullptr;
86   additional_data = nullptr;
87   PreconditionBlockBase<InverseNumberType>::clear();
88 }
89 
90 
91 template <typename MatrixType, typename InverseNumberType, typename VectorType>
92 inline void
invert_diagblocks()93 RelaxationBlock<MatrixType, InverseNumberType, VectorType>::invert_diagblocks()
94 {
95   if (this->same_diagonal())
96     {
97       Assert(false, ExcNotImplemented());
98     }
99   else
100     {
101       // compute blocks in parallel
102       parallel::apply_to_subranges(0,
103                                    this->additional_data->block_list.n_rows(),
104                                    [this](const size_type block_begin,
105                                           const size_type block_end) {
106                                      this->block_kernel(block_begin, block_end);
107                                    },
108                                    16);
109     }
110   this->inverses_computed(true);
111 }
112 
113 
114 template <typename MatrixType, typename InverseNumberType, typename VectorType>
115 inline void
block_kernel(const size_type block_begin,const size_type block_end)116 RelaxationBlock<MatrixType, InverseNumberType, VectorType>::block_kernel(
117   const size_type block_begin,
118   const size_type block_end)
119 {
120   const MatrixType &            M = *(this->A);
121   FullMatrix<InverseNumberType> M_cell;
122 
123   for (size_type block = block_begin; block < block_end; ++block)
124     {
125       const size_type bs = this->additional_data->block_list.row_length(block);
126       M_cell.reinit(bs, bs);
127 
128       // Copy rows for this block into the matrix for the diagonal block
129       SparsityPattern::iterator row =
130         this->additional_data->block_list.begin(block);
131       for (size_type row_cell = 0; row_cell < bs; ++row_cell, ++row)
132         {
133           for (typename MatrixType::const_iterator entry =
134                  M.begin(row->column());
135                entry != M.end(row->column());
136                ++entry)
137             {
138               const size_type column = entry->column();
139               const size_type col_cell =
140                 this->additional_data->block_list.row_position(block, column);
141               if (col_cell != numbers::invalid_size_type)
142                 M_cell(row_cell, col_cell) = entry->value();
143             }
144         }
145       // Now M_cell contains the diagonal block. Now store it and its
146       // inverse, if so requested.
147       if (this->store_diagonals())
148         {
149           this->diagonal(block).reinit(bs, bs);
150           this->diagonal(block) = M_cell;
151         }
152       switch (this->inversion)
153         {
154           case PreconditionBlockBase<InverseNumberType>::gauss_jordan:
155             this->inverse(block).reinit(bs, bs);
156             this->inverse(block).invert(M_cell);
157             break;
158           case PreconditionBlockBase<InverseNumberType>::householder:
159             this->inverse_householder(block).initialize(M_cell);
160             break;
161           case PreconditionBlockBase<InverseNumberType>::svd:
162             this->inverse_svd(block).reinit(bs, bs);
163             this->inverse_svd(block) = M_cell;
164             if (this->additional_data->kernel_size > 0)
165               this->inverse_svd(block).compute_inverse_svd_with_kernel(
166                 this->additional_data->kernel_size);
167             else
168               this->inverse_svd(block).compute_inverse_svd(
169                 this->additional_data->threshold);
170             break;
171           default:
172             Assert(false, ExcNotImplemented());
173         }
174     }
175 }
176 
177 namespace internal
178 {
179   /**
180    * Default implementation for serial vectors. Here we don't need to make a
181    * copy into a ghosted vector, so just return a reference to @p prev.
182    */
183   template <class VectorType>
184   const VectorType &
prepare_ghost_vector(const VectorType & prev,VectorType * other)185   prepare_ghost_vector(const VectorType &prev, VectorType *other)
186   {
187     // If the following Assertion triggers, you either set temp_ghost_vector
188     // for a serial computation (don't!), or nobody implemented, instantiated,
189     // and tested the parallel version for your vector type.
190     Assert(other == nullptr, ExcNotImplemented());
191     (void)other;
192     return prev;
193   }
194 
195 #ifdef DEAL_II_WITH_TRILINOS
196   /**
197    * Specialization for Trilinos. Use the ghosted vector.
198    */
199   template <>
200   const TrilinosWrappers::MPI::Vector &
prepare_ghost_vector(const TrilinosWrappers::MPI::Vector & prev,TrilinosWrappers::MPI::Vector * other)201   prepare_ghost_vector(const TrilinosWrappers::MPI::Vector &prev,
202                        TrilinosWrappers::MPI::Vector *      other)
203   {
204     Assert(
205       other != nullptr,
206       ExcMessage(
207         "You need to provide a ghosted vector in RelaxationBlock::AdditionalData::temp_trilinos_ghost_vector."));
208     Assert(other->size() == prev.size(), ExcInternalError());
209 
210     // import ghost values:
211     *other = prev;
212     return *other;
213   }
214 #endif // DEAL_II_WITH_TRILINOS
215 } // end namespace internal
216 
217 template <typename MatrixType, typename InverseNumberType, typename VectorType>
218 inline void
do_step(VectorType & dst,const VectorType & prev,const VectorType & src,const bool backward)219 RelaxationBlock<MatrixType, InverseNumberType, VectorType>::do_step(
220   VectorType &      dst,
221   const VectorType &prev,
222   const VectorType &src,
223   const bool        backward) const
224 {
225   Assert(additional_data->invert_diagonal, ExcNotImplemented());
226 
227   const VectorType &ghosted_prev =
228     internal::prepare_ghost_vector(prev, additional_data->temp_ghost_vector);
229 
230   const MatrixType &                      M = *this->A;
231   Vector<typename VectorType::value_type> b_cell, x_cell;
232 
233   const bool         permutation_empty = additional_data->order.size() == 0;
234   const unsigned int n_permutations =
235     (permutation_empty) ? 1U : additional_data->order.size();
236   const size_type n_blocks = additional_data->block_list.n_rows();
237 
238   if (!permutation_empty)
239     for (unsigned int i = 0; i < additional_data->order.size(); ++i)
240       AssertDimension(additional_data->order[i].size(), this->size());
241 
242   for (unsigned int perm = 0; perm < n_permutations; ++perm)
243     {
244       for (unsigned int bi = 0; bi < n_blocks; ++bi)
245         {
246           const unsigned int raw_block = backward ? (n_blocks - bi - 1) : bi;
247           const unsigned int block =
248             permutation_empty ?
249               raw_block :
250               (backward ? (additional_data
251                              ->order[n_permutations - 1 - perm][raw_block]) :
252                           (additional_data->order[perm][raw_block]));
253 
254           const size_type bs = additional_data->block_list.row_length(block);
255 
256           b_cell.reinit(bs);
257           x_cell.reinit(bs);
258           // Collect off-diagonal parts
259           SparsityPattern::iterator row =
260             additional_data->block_list.begin(block);
261           for (size_type row_cell = 0; row_cell < bs; ++row_cell, ++row)
262             {
263               b_cell(row_cell) = src(row->column());
264               for (typename MatrixType::const_iterator entry =
265                      M.begin(row->column());
266                    entry != M.end(row->column());
267                    ++entry)
268                 b_cell(row_cell) -=
269                   entry->value() * ghosted_prev(entry->column());
270             }
271           // Apply inverse diagonal
272           this->inverse_vmult(block, x_cell, b_cell);
273 #ifdef DEBUG
274           for (unsigned int i = 0; i < x_cell.size(); ++i)
275             {
276               AssertIsFinite(x_cell(i));
277             }
278 #endif
279           // Store in result vector
280           row = additional_data->block_list.begin(block);
281           for (size_type row_cell = 0; row_cell < bs; ++row_cell, ++row)
282             dst(row->column()) +=
283               additional_data->relaxation * x_cell(row_cell);
284         }
285     }
286   dst.compress(dealii::VectorOperation::add);
287 }
288 
289 
290 //----------------------------------------------------------------------//
291 
292 template <typename MatrixType, typename InverseNumberType, typename VectorType>
293 void
step(VectorType & dst,const VectorType & src)294 RelaxationBlockJacobi<MatrixType, InverseNumberType, VectorType>::step(
295   VectorType &      dst,
296   const VectorType &src) const
297 {
298   GrowingVectorMemory<VectorType>            mem;
299   typename VectorMemory<VectorType>::Pointer aux(mem);
300   aux->reinit(dst, false);
301   *aux = dst;
302   this->do_step(dst, *aux, src, false);
303 }
304 
305 
306 template <typename MatrixType, typename InverseNumberType, typename VectorType>
307 void
Tstep(VectorType & dst,const VectorType & src)308 RelaxationBlockJacobi<MatrixType, InverseNumberType, VectorType>::Tstep(
309   VectorType &      dst,
310   const VectorType &src) const
311 {
312   GrowingVectorMemory<VectorType>            mem;
313   typename VectorMemory<VectorType>::Pointer aux(mem);
314   aux->reinit(dst, false);
315   *aux = dst;
316   this->do_step(dst, *aux, src, true);
317 }
318 
319 
320 template <typename MatrixType, typename InverseNumberType, typename VectorType>
321 void
vmult(VectorType & dst,const VectorType & src)322 RelaxationBlockJacobi<MatrixType, InverseNumberType, VectorType>::vmult(
323   VectorType &      dst,
324   const VectorType &src) const
325 {
326   GrowingVectorMemory<VectorType>            mem;
327   typename VectorMemory<VectorType>::Pointer aux(mem);
328   dst = 0;
329   aux->reinit(dst);
330   this->do_step(dst, *aux, src, false);
331 }
332 
333 
334 template <typename MatrixType, typename InverseNumberType, typename VectorType>
335 void
Tvmult(VectorType & dst,const VectorType & src)336 RelaxationBlockJacobi<MatrixType, InverseNumberType, VectorType>::Tvmult(
337   VectorType &      dst,
338   const VectorType &src) const
339 {
340   GrowingVectorMemory<VectorType>            mem;
341   typename VectorMemory<VectorType>::Pointer aux(mem);
342   dst = 0;
343   aux->reinit(dst);
344   this->do_step(dst, *aux, src, true);
345 }
346 
347 
348 //----------------------------------------------------------------------//
349 
350 template <typename MatrixType, typename InverseNumberType, typename VectorType>
351 void
step(VectorType & dst,const VectorType & src)352 RelaxationBlockSOR<MatrixType, InverseNumberType, VectorType>::step(
353   VectorType &      dst,
354   const VectorType &src) const
355 {
356   this->do_step(dst, dst, src, false);
357 }
358 
359 
360 template <typename MatrixType, typename InverseNumberType, typename VectorType>
361 void
Tstep(VectorType & dst,const VectorType & src)362 RelaxationBlockSOR<MatrixType, InverseNumberType, VectorType>::Tstep(
363   VectorType &      dst,
364   const VectorType &src) const
365 {
366   this->do_step(dst, dst, src, true);
367 }
368 
369 
370 template <typename MatrixType, typename InverseNumberType, typename VectorType>
371 void
vmult(VectorType & dst,const VectorType & src)372 RelaxationBlockSOR<MatrixType, InverseNumberType, VectorType>::vmult(
373   VectorType &      dst,
374   const VectorType &src) const
375 {
376   dst = 0;
377   this->do_step(dst, dst, src, false);
378 }
379 
380 
381 template <typename MatrixType, typename InverseNumberType, typename VectorType>
382 void
Tvmult(VectorType & dst,const VectorType & src)383 RelaxationBlockSOR<MatrixType, InverseNumberType, VectorType>::Tvmult(
384   VectorType &      dst,
385   const VectorType &src) const
386 {
387   dst = 0;
388   this->do_step(dst, dst, src, true);
389 }
390 
391 
392 //----------------------------------------------------------------------//
393 
394 template <typename MatrixType, typename InverseNumberType, typename VectorType>
395 void
step(VectorType & dst,const VectorType & src)396 RelaxationBlockSSOR<MatrixType, InverseNumberType, VectorType>::step(
397   VectorType &      dst,
398   const VectorType &src) const
399 {
400   this->do_step(dst, dst, src, false);
401   this->do_step(dst, dst, src, true);
402 }
403 
404 
405 template <typename MatrixType, typename InverseNumberType, typename VectorType>
406 void
Tstep(VectorType & dst,const VectorType & src)407 RelaxationBlockSSOR<MatrixType, InverseNumberType, VectorType>::Tstep(
408   VectorType &      dst,
409   const VectorType &src) const
410 {
411   this->do_step(dst, dst, src, true);
412   this->do_step(dst, dst, src, false);
413 }
414 
415 
416 template <typename MatrixType, typename InverseNumberType, typename VectorType>
417 void
vmult(VectorType & dst,const VectorType & src)418 RelaxationBlockSSOR<MatrixType, InverseNumberType, VectorType>::vmult(
419   VectorType &      dst,
420   const VectorType &src) const
421 {
422   dst = 0;
423   this->do_step(dst, dst, src, false);
424   this->do_step(dst, dst, src, true);
425 }
426 
427 
428 template <typename MatrixType, typename InverseNumberType, typename VectorType>
429 void
Tvmult(VectorType & dst,const VectorType & src)430 RelaxationBlockSSOR<MatrixType, InverseNumberType, VectorType>::Tvmult(
431   VectorType &      dst,
432   const VectorType &src) const
433 {
434   dst = 0;
435   this->do_step(dst, dst, src, true);
436   this->do_step(dst, dst, src, false);
437 }
438 
439 
440 
441 DEAL_II_NAMESPACE_CLOSE
442 
443 
444 #endif
445