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