Reference documentation for deal.II version 9.1.0-pre
matrix_tools_once.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2017 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 #include <deal.II/base/function.h>
17 #include <deal.II/base/geometry_info.h>
18 #include <deal.II/base/quadrature.h>
19 #include <deal.II/base/work_stream.h>
20 
21 #include <deal.II/dofs/dof_accessor.h>
22 #include <deal.II/dofs/dof_handler.h>
23 #include <deal.II/dofs/dof_tools.h>
24 
25 #include <deal.II/fe/fe.h>
26 #include <deal.II/fe/fe_values.h>
27 #include <deal.II/fe/mapping_q1.h>
28 
29 #include <deal.II/grid/tria_iterator.h>
30 
31 #include <deal.II/hp/fe_values.h>
32 #include <deal.II/hp/mapping_collection.h>
33 
34 #include <deal.II/lac/block_sparse_matrix.h>
35 #include <deal.II/lac/block_vector.h>
36 #include <deal.II/lac/full_matrix.h>
37 #include <deal.II/lac/sparse_matrix.h>
38 #include <deal.II/lac/vector.h>
39 
40 #include <deal.II/numerics/matrix_tools.h>
41 
42 #ifdef DEAL_II_WITH_PETSC
43 # include <deal.II/lac/petsc_block_sparse_matrix.h>
44 # include <deal.II/lac/petsc_block_vector.h>
45 # include <deal.II/lac/petsc_matrix_base.h>
46 # include <deal.II/lac/petsc_vector_base.h>
47 #endif
48 
49 #ifdef DEAL_II_WITH_TRILINOS
50 # include <deal.II/lac/trilinos_block_sparse_matrix.h>
51 # include <deal.II/lac/trilinos_parallel_block_vector.h>
52 # include <deal.II/lac/trilinos_sparse_matrix.h>
53 # include <deal.II/lac/trilinos_vector.h>
54 #endif
55 
56 #include <algorithm>
57 #include <cmath>
58 
59 
60 DEAL_II_NAMESPACE_OPEN
61 
62 namespace MatrixTools
63 {
64 #ifdef DEAL_II_WITH_PETSC
65  void
67  const std::map<types::global_dof_index, PetscScalar> &boundary_values,
69  PETScWrappers::VectorBase & solution,
70  PETScWrappers::VectorBase & right_hand_side,
71  const bool eliminate_columns)
72  {
73  (void)eliminate_columns;
74  Assert(eliminate_columns == false, ExcNotImplemented());
75 
76  Assert(matrix.n() == right_hand_side.size(),
77  ExcDimensionMismatch(matrix.n(), right_hand_side.size()));
78  Assert(matrix.n() == solution.size(),
79  ExcDimensionMismatch(matrix.n(), solution.size()));
80 
81  // if no boundary values are to be applied, then
82  // jump straight to the compress() calls that we still have
83  // to perform because they are collective operations
84  if (boundary_values.size() > 0)
85  {
86  const std::pair<types::global_dof_index, types::global_dof_index>
87  local_range = matrix.local_range();
88  Assert(local_range == right_hand_side.local_range(),
90  Assert(local_range == solution.local_range(), ExcInternalError());
91 
92  // determine the first nonzero diagonal
93  // entry from within the part of the
94  // matrix that we can see. if we can't
95  // find such an entry, take one
96  PetscScalar average_nonzero_diagonal_entry = 1;
97  for (types::global_dof_index i = local_range.first;
98  i < local_range.second;
99  ++i)
100  if (matrix.diag_element(i) != PetscScalar())
101  {
102  average_nonzero_diagonal_entry = std::abs(matrix.diag_element(i));
103  break;
104  }
105 
106  // figure out which rows of the matrix we
107  // have to eliminate on this processor
108  std::vector<types::global_dof_index> constrained_rows;
109  for (std::map<types::global_dof_index, PetscScalar>::const_iterator
110  dof = boundary_values.begin();
111  dof != boundary_values.end();
112  ++dof)
113  if ((dof->first >= local_range.first) &&
114  (dof->first < local_range.second))
115  constrained_rows.push_back(dof->first);
116 
117  // then eliminate these rows and set
118  // their diagonal entry to what we have
119  // determined above. note that for petsc
120  // matrices interleaving read with write
121  // operations is very expensive. thus, we
122  // here always replace the diagonal
123  // element, rather than first checking
124  // whether it is nonzero and in that case
125  // preserving it. this is different from
126  // the case of deal.II sparse matrices
127  // treated in the other functions.
128  matrix.clear_rows(constrained_rows, average_nonzero_diagonal_entry);
129 
130  std::vector<types::global_dof_index> indices;
131  std::vector<PetscScalar> solution_values;
132  for (std::map<types::global_dof_index, PetscScalar>::const_iterator
133  dof = boundary_values.begin();
134  dof != boundary_values.end();
135  ++dof)
136  if ((dof->first >= local_range.first) &&
137  (dof->first < local_range.second))
138  {
139  indices.push_back(dof->first);
140  solution_values.push_back(dof->second);
141  }
142  solution.set(indices, solution_values);
143 
144  // now also set appropriate values for
145  // the rhs
146  for (unsigned int i = 0; i < solution_values.size(); ++i)
147  solution_values[i] *= average_nonzero_diagonal_entry;
148 
149  right_hand_side.set(indices, solution_values);
150  }
151  else
152  {
153  // clear_rows() is a collective operation so we still have to call
154  // it:
155  std::vector<types::global_dof_index> constrained_rows;
156  matrix.clear_rows(constrained_rows, 1.);
157  }
158 
159  // clean up
161  right_hand_side.compress(VectorOperation::insert);
162  }
163 
164 
165  void
167  const std::map<types::global_dof_index, PetscScalar> &boundary_values,
170  PETScWrappers::MPI::BlockVector & right_hand_side,
171  const bool eliminate_columns)
172  {
173  Assert(matrix.n() == right_hand_side.size(),
174  ExcDimensionMismatch(matrix.n(), right_hand_side.size()));
175  Assert(matrix.n() == solution.size(),
176  ExcDimensionMismatch(matrix.n(), solution.size()));
177  Assert(matrix.n_block_rows() == matrix.n_block_cols(), ExcNotQuadratic());
178 
179  const unsigned int n_blocks = matrix.n_block_rows();
180 
181  // We need to find the subdivision
182  // into blocks for the boundary values.
183  // To this end, generate a vector of
184  // maps with the respective indices.
185  std::vector<std::map<::types::global_dof_index, PetscScalar>>
186  block_boundary_values(n_blocks);
187  {
188  int block = 0;
189  ::types::global_dof_index offset = 0;
190  for (std::map<types::global_dof_index, PetscScalar>::const_iterator dof =
191  boundary_values.begin();
192  dof != boundary_values.end();
193  ++dof)
194  {
195  if (dof->first >= matrix.block(block, 0).m() + offset)
196  {
197  offset += matrix.block(block, 0).m();
198  block++;
199  }
200  const types::global_dof_index index = dof->first - offset;
201  block_boundary_values[block].insert(
202  std::pair<types::global_dof_index, PetscScalar>(index,
203  dof->second));
204  }
205  }
206 
207  // Now call the non-block variants on
208  // the diagonal subblocks and the
209  // solution/rhs.
210  for (unsigned int block = 0; block < n_blocks; ++block)
211  apply_boundary_values(block_boundary_values[block],
212  matrix.block(block, block),
213  solution.block(block),
214  right_hand_side.block(block),
215  eliminate_columns);
216 
217  // Finally, we need to do something
218  // about the off-diagonal matrices. This
219  // is luckily not difficult. Just clear
220  // the whole row.
221  for (unsigned int block_m = 0; block_m < n_blocks; ++block_m)
222  {
223  const std::pair<types::global_dof_index, types::global_dof_index>
224  local_range = matrix.block(block_m, 0).local_range();
225 
226  std::vector<types::global_dof_index> constrained_rows;
227  for (std::map<types::global_dof_index, PetscScalar>::const_iterator
228  dof = block_boundary_values[block_m].begin();
229  dof != block_boundary_values[block_m].end();
230  ++dof)
231  if ((dof->first >= local_range.first) &&
232  (dof->first < local_range.second))
233  constrained_rows.push_back(dof->first);
234 
235  for (unsigned int block_n = 0; block_n < n_blocks; ++block_n)
236  if (block_m != block_n)
237  matrix.block(block_m, block_n).clear_rows(constrained_rows);
238  }
239  }
240 
241 #endif
242 
243 
244 
245 #ifdef DEAL_II_WITH_TRILINOS
246 
247  namespace internal
248  {
249  namespace TrilinosWrappers
250  {
251  template <typename TrilinosMatrix, typename TrilinosVector>
252  void
254  TrilinosScalar> &boundary_values,
255  TrilinosMatrix & matrix,
256  TrilinosVector & solution,
257  TrilinosVector & right_hand_side,
258  const bool eliminate_columns)
259  {
260  Assert(eliminate_columns == false, ExcNotImplemented());
261  (void)eliminate_columns;
262 
263  Assert(matrix.n() == right_hand_side.size(),
264  ExcDimensionMismatch(matrix.n(), right_hand_side.size()));
265  Assert(matrix.n() == solution.size(),
266  ExcDimensionMismatch(matrix.m(), solution.size()));
267 
268  // if no boundary values are to be applied, then
269  // jump straight to the compress() calls that we still have
270  // to perform because they are collective operations
271  if (boundary_values.size() > 0)
272  {
273  const std::pair<types::global_dof_index, types::global_dof_index>
274  local_range = matrix.local_range();
275  Assert(local_range == right_hand_side.local_range(),
276  ExcInternalError());
277  Assert(local_range == solution.local_range(), ExcInternalError());
278 
279  // determine the first nonzero diagonal
280  // entry from within the part of the
281  // matrix that we can see. if we can't
282  // find such an entry, take one
283  TrilinosScalar average_nonzero_diagonal_entry = 1;
284  for (types::global_dof_index i = local_range.first;
285  i < local_range.second;
286  ++i)
287  if (matrix.diag_element(i) != 0)
288  {
289  average_nonzero_diagonal_entry =
290  std::fabs(matrix.diag_element(i));
291  break;
292  }
293 
294  // figure out which rows of the matrix we
295  // have to eliminate on this processor
296  std::vector<types::global_dof_index> constrained_rows;
297  for (std::map<types::global_dof_index,
298  TrilinosScalar>::const_iterator dof =
299  boundary_values.begin();
300  dof != boundary_values.end();
301  ++dof)
302  if ((dof->first >= local_range.first) &&
303  (dof->first < local_range.second))
304  constrained_rows.push_back(dof->first);
305 
306  // then eliminate these rows and
307  // set their diagonal entry to
308  // what we have determined
309  // above. if the value already is
310  // nonzero, it will be preserved,
311  // in accordance with the basic
312  // matrix classes in deal.II.
313  matrix.clear_rows(constrained_rows, average_nonzero_diagonal_entry);
314 
315  std::vector<types::global_dof_index> indices;
316  std::vector<TrilinosScalar> solution_values;
317  for (std::map<types::global_dof_index,
318  TrilinosScalar>::const_iterator dof =
319  boundary_values.begin();
320  dof != boundary_values.end();
321  ++dof)
322  if ((dof->first >= local_range.first) &&
323  (dof->first < local_range.second))
324  {
325  indices.push_back(dof->first);
326  solution_values.push_back(dof->second);
327  }
328  solution.set(indices, solution_values);
329 
330  // now also set appropriate
331  // values for the rhs
332  for (unsigned int i = 0; i < solution_values.size(); ++i)
333  solution_values[i] *= matrix.diag_element(indices[i]);
334 
335  right_hand_side.set(indices, solution_values);
336  }
337  else
338  {
339  // clear_rows() is a collective operation so we still have to call
340  // it:
341  std::vector<types::global_dof_index> constrained_rows;
342  matrix.clear_rows(constrained_rows, 1.);
343  }
344 
345  // clean up
346  matrix.compress(VectorOperation::insert);
347  solution.compress(VectorOperation::insert);
348  right_hand_side.compress(VectorOperation::insert);
349  }
350 
351 
352 
353  template <typename TrilinosMatrix, typename TrilinosBlockVector>
354  void
355  apply_block_boundary_values(
356  const std::map<types::global_dof_index, TrilinosScalar>
357  & boundary_values,
358  TrilinosMatrix & matrix,
359  TrilinosBlockVector &solution,
360  TrilinosBlockVector &right_hand_side,
361  const bool eliminate_columns)
362  {
363  Assert(eliminate_columns == false, ExcNotImplemented());
364 
365  Assert(matrix.n() == right_hand_side.size(),
366  ExcDimensionMismatch(matrix.n(), right_hand_side.size()));
367  Assert(matrix.n() == solution.size(),
368  ExcDimensionMismatch(matrix.n(), solution.size()));
369  Assert(matrix.n_block_rows() == matrix.n_block_cols(),
370  ExcNotQuadratic());
371 
372  const unsigned int n_blocks = matrix.n_block_rows();
373 
374  // We need to find the subdivision
375  // into blocks for the boundary values.
376  // To this end, generate a vector of
377  // maps with the respective indices.
378  std::vector<std::map<types::global_dof_index, TrilinosScalar>>
379  block_boundary_values(n_blocks);
380  {
381  int block = 0;
382  types::global_dof_index offset = 0;
383  for (std::map<types::global_dof_index, TrilinosScalar>::const_iterator
384  dof = boundary_values.begin();
385  dof != boundary_values.end();
386  ++dof)
387  {
388  if (dof->first >= matrix.block(block, 0).m() + offset)
389  {
390  offset += matrix.block(block, 0).m();
391  block++;
392  }
393  const types::global_dof_index index = dof->first - offset;
394  block_boundary_values[block].insert(
395  std::pair<types::global_dof_index, TrilinosScalar>(
396  index, dof->second));
397  }
398  }
399 
400  // Now call the non-block variants on
401  // the diagonal subblocks and the
402  // solution/rhs.
403  for (unsigned int block = 0; block < n_blocks; ++block)
404  TrilinosWrappers::apply_boundary_values(block_boundary_values[block],
405  matrix.block(block, block),
406  solution.block(block),
407  right_hand_side.block(block),
408  eliminate_columns);
409 
410  // Finally, we need to do something
411  // about the off-diagonal matrices. This
412  // is luckily not difficult. Just clear
413  // the whole row.
414  for (unsigned int block_m = 0; block_m < n_blocks; ++block_m)
415  {
416  const std::pair<types::global_dof_index, types::global_dof_index>
417  local_range = matrix.block(block_m, 0).local_range();
418 
419  std::vector<types::global_dof_index> constrained_rows;
420  for (std::map<types::global_dof_index,
421  TrilinosScalar>::const_iterator dof =
422  block_boundary_values[block_m].begin();
423  dof != block_boundary_values[block_m].end();
424  ++dof)
425  if ((dof->first >= local_range.first) &&
426  (dof->first < local_range.second))
427  constrained_rows.push_back(dof->first);
428 
429  for (unsigned int block_n = 0; block_n < n_blocks; ++block_n)
430  if (block_m != block_n)
431  matrix.block(block_m, block_n).clear_rows(constrained_rows);
432  }
433  }
434  } // namespace TrilinosWrappers
435  } // namespace internal
436 
437 
438 
439  void
441  const std::map<types::global_dof_index, TrilinosScalar> &boundary_values,
444  TrilinosWrappers::MPI::Vector & right_hand_side,
445  const bool eliminate_columns)
446  {
447  // simply redirect to the generic function
448  // used for both trilinos matrix types
449  internal::TrilinosWrappers::apply_boundary_values(
450  boundary_values, matrix, solution, right_hand_side, eliminate_columns);
451  }
452 
453 
454 
455  void
457  const std::map<types::global_dof_index, TrilinosScalar> &boundary_values,
460  TrilinosWrappers::MPI::BlockVector & right_hand_side,
461  const bool eliminate_columns)
462  {
463  internal::TrilinosWrappers::apply_block_boundary_values(
464  boundary_values, matrix, solution, right_hand_side, eliminate_columns);
465  }
466 
467 #endif
468 
469 } // namespace MatrixTools
470 
471 DEAL_II_NAMESPACE_CLOSE
std::size_t size() const
void apply_boundary_values(const std::map< types::global_dof_index, number > &boundary_values, SparseMatrix< number > &matrix, Vector< number > &solution, Vector< number > &right_hand_side, const bool eliminate_columns=true)
Definition: matrix_tools.cc:81
size_type n() const
size_type m() const
unsigned int n_block_cols() const
unsigned long long int global_dof_index
Definition: types.h:72
void clear_rows(const std::vector< size_type > &rows, const PetscScalar new_diag_value=0)
void compress(const VectorOperation::values operation)
#define Assert(cond, exc)
Definition: exceptions.h:1227
static::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
std::pair< size_type, size_type > local_range() const
PetscScalar diag_element(const size_type i) const
static::ExceptionBase & ExcNotQuadratic()
BlockType & block(const unsigned int row, const unsigned int column)
static::ExceptionBase & ExcNotImplemented()
BlockType & block(const unsigned int i)
unsigned int n_block_rows() const
static::ExceptionBase & ExcInternalError()
void set(const std::vector< size_type > &indices, const std::vector< PetscScalar > &values)
std::pair< size_type, size_type > local_range() const