Reference documentation for deal.II version 9.0.0
constrained_linear_operator.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2015 - 2018 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 #ifndef dealii_constrained_linear_operator_h
17 #define dealii_constrained_linear_operator_h
18 
19 #include <deal.II/lac/linear_operator.h>
20 #include <deal.II/lac/packaged_operation.h>
21 #include <deal.II/lac/constraint_matrix.h>
22 
23 
24 DEAL_II_NAMESPACE_OPEN
25 
26 
31 
32 
62 template <typename Range, typename Domain>
64  const ConstraintMatrix &constraint_matrix,
65  const LinearOperator<Range, Domain> &exemplar)
66 {
67  LinearOperator<Range, Domain> return_op = exemplar;
68 
69  return_op.vmult_add = [&constraint_matrix](Range &v, const Domain &u)
70  {
72  ::ExcMessage("The domain and range vectors must be different "
73  "storage locations"));
74 
75  // First, add vector u to v unconditionally and clean up constrained
76  // degrees of freedom later.
77  v += u;
78 
79  const auto &locally_owned_elements = v.locally_owned_elements();
80  for (const auto &line : constraint_matrix.get_lines())
81  {
82  const auto i = line.index;
83  if (locally_owned_elements.is_element(i))
84  {
85  v(i) -= u(i);
86  const auto &entries = line.entries;
87  for (types::global_dof_index j = 0; j < entries.size(); ++j)
88  {
89  const auto pos = entries[j].first;
90  v(i) += u(pos) * entries[j].second;
91  }
92  }
93  }
94 
95  v.compress(VectorOperation::add);
96  };
97 
98  return_op.Tvmult_add = [&constraint_matrix](Domain &v, const Range &u)
99  {
100  Assert(!::PointerComparison::equal(&v, &u),
101  ::ExcMessage("The domain and range vectors must be different "
102  "storage locations"));
103 
104  // First, add vector u to v unconditionally and clean up constrained
105  // degrees of freedom later.
106  v += u;
107 
108  const auto &locally_owned_elements = v.locally_owned_elements();
109  for (const auto &line : constraint_matrix.get_lines())
110  {
111  const auto i = line.index;
112 
113  if (locally_owned_elements.is_element(i))
114  {
115  v(i) -= u(i);
116  }
117 
118  const auto &entries = line.entries;
119  for (types::global_dof_index j = 0; j < entries.size(); ++j)
120  {
121  const auto pos = entries[j].first;
122  if (locally_owned_elements.is_element(pos))
123  v(pos) += u(i) * entries[j].second;
124  }
125  }
126 
127  v.compress(VectorOperation::add);
128  };
129 
130  // lambda capture expressions are a C++14 feature...
131  const auto vmult_add = return_op.vmult_add;
132  return_op.vmult = [vmult_add](Range &v, const Domain &u)
133  {
134  v = 0.;
135  vmult_add(v, u);
136  };
137 
138  // lambda capture expressions are a C++14 feature...
139  const auto Tvmult_add = return_op.Tvmult_add;
140  return_op.Tvmult = [Tvmult_add](Domain &v, const Range &u)
141  {
142  v = 0.;
143  Tvmult_add(v, u);
144  };
145 
146  return return_op;
147 }
148 
149 
161 template <typename Range, typename Domain>
163  const ConstraintMatrix &constraint_matrix,
164  const LinearOperator<Range, Domain> &exemplar)
165 {
166  LinearOperator<Range, Domain> return_op = exemplar;
167 
168  return_op.vmult_add = [&constraint_matrix](Range &v, const Domain &u)
169  {
170  const auto &locally_owned_elements = v.locally_owned_elements();
171  for (const auto &line : constraint_matrix.get_lines())
172  {
173  const auto i = line.index;
174  if (locally_owned_elements.is_element(i))
175  {
176  v(i) += u(i);
177  }
178  }
179 
180  v.compress(VectorOperation::add);
181  };
182 
183  return_op.Tvmult_add = [&constraint_matrix](Domain &v, const Range &u)
184  {
185  const auto &locally_owned_elements = v.locally_owned_elements();
186  for (const auto &line : constraint_matrix.get_lines())
187  {
188  const auto i = line.index;
189  if (locally_owned_elements.is_element(i))
190  {
191  v(i) += u(i);
192  }
193  }
194 
195  v.compress(VectorOperation::add);
196  };
197 
198  // lambda capture expressions are a C++14 feature...
199  const auto vmult_add = return_op.vmult_add;
200  return_op.vmult = [vmult_add](Range &v, const Domain &u)
201  {
202  v = 0.;
203  vmult_add(v, u);
204  };
205 
206  // lambda capture expressions are a C++14 feature...
207  const auto Tvmult_add = return_op.Tvmult_add;
208  return_op.Tvmult = [Tvmult_add](Domain &v, const Range &u)
209  {
210  v = 0.;
211  Tvmult_add(v, u);
212  };
213 
214  return return_op;
215 }
216 
217 
255 template <typename Range, typename Domain>
258  const LinearOperator<Range, Domain> &linop)
259 {
260  const auto C =
261  distribute_constraints_linear_operator(constraint_matrix, linop);
262  const auto Ct = transpose_operator(C);
263  const auto Id_c =
264  project_to_constrained_linear_operator(constraint_matrix, linop);
265  return Ct * linop * C + Id_c;
266 }
267 
268 
303 template <typename Range, typename Domain>
306  const LinearOperator<Range, Domain> &linop,
307  const Range &right_hand_side)
308 {
309  PackagedOperation<Range> return_comp;
310 
311  return_comp.reinit_vector = linop.reinit_range_vector;
312 
313  return_comp.apply_add =
314  [&constraint_matrix, &linop, &right_hand_side](Range &v)
315  {
316  const auto C =
317  distribute_constraints_linear_operator(constraint_matrix, linop);
318  const auto Ct = transpose_operator(C);
319 
320  GrowingVectorMemory<Domain> vector_memory;
321  typename VectorMemory<Domain>::Pointer k (vector_memory);
322  linop.reinit_domain_vector(*k, /*bool fast=*/ false);
323  constraint_matrix.distribute(*k);
324 
325  v += Ct * (right_hand_side - linop **k);
326  };
327 
328  // lambda capture expressions are a C++14 feature...
329  const auto apply_add = return_comp.apply_add;
330  return_comp.apply = [apply_add](Range &v)
331  {
332  v = 0.;
333  apply_add(v);
334  };
335 
336  return return_comp;
337 }
338 
340 
341 DEAL_II_NAMESPACE_CLOSE
342 
343 #endif
std::function< void(Range &v)> apply
LinearOperator< Range, Domain > project_to_constrained_linear_operator(const ConstraintMatrix &constraint_matrix, const LinearOperator< Range, Domain > &exemplar)
std::function< void(Range &v, bool omit_zeroing_entries)> reinit_vector
std::function< void(Range &v, bool omit_zeroing_entries)> reinit_range_vector
std::function< void(Domain &v, const Range &u)> Tvmult_add
std::function< void(Domain &v, const Range &u)> Tvmult
LinearOperator< Domain, Range, Payload > transpose_operator(const LinearOperator< Range, Domain, Payload > &op)
static ::ExceptionBase & ExcMessage(std::string arg1)
LinearOperator< Range, Domain > constrained_linear_operator(const ConstraintMatrix &constraint_matrix, const LinearOperator< Range, Domain > &linop)
PackagedOperation< Range > constrained_right_hand_side(const ConstraintMatrix &constraint_matrix, const LinearOperator< Range, Domain > &linop, const Range &right_hand_side)
unsigned int global_dof_index
Definition: types.h:88
#define Assert(cond, exc)
Definition: exceptions.h:1142
std::function< void(Range &v, const Domain &u)> vmult
std::function< void(Range &v)> apply_add
void distribute(VectorType &vec) const
std::function< void(Range &v, const Domain &u)> vmult_add
LinearOperator< Range, Domain > distribute_constraints_linear_operator(const ConstraintMatrix &constraint_matrix, const LinearOperator< Range, Domain > &exemplar)
const LineRange get_lines() const
static bool equal(const T *p1, const T *p2)