Reference documentation for deal.II version 8.4.2
schur_complement.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2015 - 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 #ifndef dealii__schur_complement_h
17 #define dealii__schur_complement_h
18 
19 #include <deal.II/base/config.h>
20 #include <deal.II/base/exceptions.h>
21 #include <deal.II/lac/vector_memory.h>
22 #include <deal.II/lac/linear_operator.h>
23 #include <deal.II/lac/packaged_operation.h>
24 
25 #ifdef DEAL_II_WITH_CXX11
26 
27 DEAL_II_NAMESPACE_OPEN
28 
33 
226 template <typename Range_1, typename Domain_1,
227  typename Range_2, typename Domain_2>
233 {
235 
238 
239  // ensure to have valid computation objects by catching
240  // A_inv,B,C,D by value
241 
242  return_op.vmult_add = [A_inv,B,C,D](Range_2 &dst_g, const Domain_2 &src_y)
243  {
244  static GrowingVectorMemory<Range_1> vector_memory_f;
245  static GrowingVectorMemory<Range_2> vector_memory_g;
246  static GrowingVectorMemory<Domain_1> vector_memory_x;
247 
248  Range_1 &tmp_f = *(vector_memory_f.alloc());
249  Range_2 &tmp_g = *(vector_memory_g.alloc());
250  Domain_1 &tmp_x = *(vector_memory_x.alloc());
251 
252  // Reinitialise in context of how they'll be used
253  B.reinit_range_vector(tmp_f, /*bool omit_zeroing_entries =*/ true);
254  A_inv.reinit_range_vector(tmp_x, /*bool omit_zeroing_entries =*/ true);
255  C.reinit_range_vector(tmp_g, /*bool omit_zeroing_entries =*/ true);
256 
257  // Need to form dst_g such that dst_g = S*src_y = (D - C*A_inv*B) src_y
258  if (D.is_null_operator == false)
259  D.vmult_add (dst_g, src_y); // dst_g += D*src_y (length y)
260 
261  B.vmult (tmp_f, src_y); // tmp_f = B*src_y (length x)
262  try
263  {
264  A_inv.vmult (tmp_x, tmp_f); // tmp_x = A_inv*B*src_y (length x)
265  }
266  catch (...)
267  {
268  AssertThrow(false,
269  ExcMessage("No convergence in A_inv vmult operation"));
270  }
271  C.vmult (tmp_g, tmp_x); // tmp_g = C*A_inv*B*src_y (length y)
272  dst_g -= tmp_g; // dst_g += D*src_y - C*A_inv*B*src_y
273 
274  vector_memory_x.free(&tmp_x);
275  vector_memory_g.free(&tmp_g);
276  vector_memory_f.free(&tmp_f);
277  };
278 
279  const auto vmult_add = return_op.vmult_add;
280  return_op.vmult = [vmult_add](Range_2 &dst_g, const Domain_2 &src_y)
281  {
282  dst_g = 0.;
283  vmult_add(dst_g, src_y);
284  };
285 
286  return_op.Tvmult_add = [A_inv,B,C,D](Domain_2 &dst_g, const Range_2 &src_y)
287  {
288  static GrowingVectorMemory<Domain_1> vector_memory_f;
289  static GrowingVectorMemory<Domain_2> vector_memory_g;
290  static GrowingVectorMemory<Range_1> vector_memory_x;
291 
292  Domain_1 &tmp_f = *(vector_memory_f.alloc());
293  Domain_2 &tmp_g = *(vector_memory_g.alloc());
294  Range_1 &tmp_x = *(vector_memory_x.alloc());
295 
296  // Reinitialise in context of how they'll be used
297  C.reinit_domain_vector(tmp_f, /*bool omit_zeroing_entries =*/ true);
298  A_inv.reinit_domain_vector(tmp_x, /*bool omit_zeroing_entries =*/ true);
299  B.reinit_domain_vector(tmp_g, /*bool omit_zeroing_entries =*/ true);
300 
301  // Need to form y such that dst such that dst_g = S*src_y = (D^T - B^T*A_inv^T*C^T) src_y
302  if (D.is_null_operator == false)
303  D.Tvmult_add (dst_g, src_y); // dst_g += D^T*src_y (length y)
304 
305  C.Tvmult (tmp_f, src_y); // tmp_f = C^T*src_y (length x)
306  try
307  {
308  A_inv.Tvmult (tmp_x, tmp_f); // tmp_x = A_inv^T*C^T*src_y (length x)
309  }
310  catch (...)
311  {
312  AssertThrow(false,
313  ExcMessage("No convergence in A_inv Tvmult operation"));
314  }
315  B.Tvmult (tmp_g, tmp_x); // tmp_g = B^T*A_inv^T*C^T*src_y (length y)
316  dst_g -= tmp_g; // dst_g += D^T*src_y - B^T*A_inv^T*C^T*src_y
317 
318  vector_memory_x.free(&tmp_x);
319  vector_memory_g.free(&tmp_g);
320  vector_memory_f.free(&tmp_f);
321  };
322 
323  const auto Tvmult_add = return_op.Tvmult_add;
324  return_op.Tvmult = [Tvmult_add](Domain_2 &dst_g, const Range_2 &src_y)
325  {
326  dst_g = 0.;
327  Tvmult_add(dst_g, src_y);
328  };
329 
330  return return_op;
331 }
332 
334 
335 
340 
363 template <typename Range_1, typename Domain_1,
364  typename Range_2>
368  const Range_1 &f,
369  const Range_2 &g)
370 {
371  PackagedOperation<Range_2> return_comp;
372 
373  return_comp.reinit_vector = C.reinit_range_vector;
374 
375  // ensure to have valid computation objects by catching
376  // A_inv,C,f,g by value
377 
378  return_comp.apply_add = [A_inv,C,f,g](Range_2 &g_star)
379  {
380 
381  static GrowingVectorMemory<Range_1> vector_memory_f;
382  static GrowingVectorMemory<Range_2> vector_memory_g;
383 
384  Range_1 &tmp_f1 = *(vector_memory_f.alloc());
385  Range_2 &tmp_g1 = *(vector_memory_g.alloc());
386  Range_2 &tmp_g2 = *(vector_memory_g.alloc());
387 
388  // Reinitialise in context of how they'll be used
389  A_inv.reinit_range_vector(tmp_f1, /*bool omit_zeroing_entries =*/ true);
390  C.reinit_range_vector(tmp_g1, /*bool omit_zeroing_entries =*/ true);
391 
392  // Condensation on RHS of one field
393  // Need to form g* such that g* = g - C*A_inv*f
394  try
395  {
396  A_inv.vmult(tmp_f1, f); // tmp_f1 = A_inv * f
397  }
398  catch (...)
399  {
400  AssertThrow(false,
401  ExcMessage("No convergence in A_inv vmult operation"));
402  }
403  C.vmult(tmp_g1, tmp_f1); // tmp2 = C * A_inv * f
404 
405  g_star += g;
406  g_star -= tmp_g1; // tmp_g2 = g - C * A_inv * f
407 
408  vector_memory_g.free(&tmp_g2);
409  vector_memory_g.free(&tmp_g1);
410  vector_memory_f.free(&tmp_f1);
411  };
412 
413  const auto apply_add = return_comp.apply_add;
414  return_comp.apply = [apply_add](Range_2 &g_star)
415  {
416  g_star = 0.;
417  apply_add(g_star);
418  };
419 
420  return return_comp;
421 }
422 
444 template <typename Range_1, typename Domain_1,
445  typename Domain_2>
449  const Domain_2 &y,
450  const Range_1 &f)
451 {
452  PackagedOperation<Domain_1> return_comp;
453 
454  return_comp.reinit_vector = A_inv.reinit_domain_vector;
455 
456  // ensure to have valid computation objects by catching
457  // A_inv,B,y,f by value
458 
459  return_comp.apply_add = [A_inv,B,y,f](Domain_1 &x)
460  {
461  static GrowingVectorMemory<Range_1> vector_memory_f;
462 
463  Range_1 &tmp_f1 = *(vector_memory_f.alloc());
464  Range_1 &tmp_f2 = *(vector_memory_f.alloc());
465 
466  // Reinitialise in context of how they'll be used
467  B.reinit_range_vector(tmp_f1, /*bool omit_zeroing_entries =*/ true);
468 
469  // Solve for second field
470  // Need to form x such that x = A_inv*(f - B*y)
471  B.vmult(tmp_f1, y); // tmp_f1 = B*y
472  tmp_f2 = f;
473  tmp_f2 -= tmp_f1; // tmp_f2 = f - B*y
474  try
475  {
476  A_inv.vmult_add(x, tmp_f2); // x = A_inv*(f-B*y)
477  }
478  catch (...)
479  {
480  AssertThrow(false,
481  ExcMessage("No convergence in A_inv vmult operation"));
482  }
483 
484  vector_memory_f.free(&tmp_f2);
485  vector_memory_f.free(&tmp_f1);
486  };
487 
488  const auto apply_add = return_comp.apply_add;
489  return_comp.apply = [apply_add](Domain_1 &x)
490  {
491  x = 0.;
492  apply_add(x);
493  };
494 
495  return return_comp;
496 }
497 
499 
500 DEAL_II_NAMESPACE_CLOSE
501 
502 #endif // DEAL_II_WITH_CXX11
503 #endif
PackagedOperation< Domain_1 > postprocess_schur_solution(const LinearOperator< Range_1, Domain_1 > &A_inv, const LinearOperator< Range_1, Domain_2 > &B, const Domain_2 &y, const Range_1 &f)
std::function< void(Range &v)> apply
std::function< void(Range &v, bool omit_zeroing_entries)> reinit_vector
::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
std::function< void(Range &v, bool omit_zeroing_entries)> reinit_range_vector
std::function< void(Domain &v, const Range &u)> Tvmult_add
virtual VectorType * alloc()
LinearOperator< Range_2, Domain_2 > schur_complement(const LinearOperator< Domain_1, Range_1 > &A_inv, const LinearOperator< Range_1, Domain_2 > &B, const LinearOperator< Range_2, Domain_1 > &C, const LinearOperator< Range_2, Domain_2 > &D)
virtual void free(const VectorType *const)
std::function< void(Domain &v, bool omit_zeroing_entries)> reinit_domain_vector
std::function< void(Range &v)> apply_add
std::function< void(Range &v, const Domain &u)> vmult
std::function< void(Range &v, const Domain &u)> vmult_add
std::function< void(Domain &v, const Range &u)> Tvmult
PackagedOperation< Range_2 > condense_schur_rhs(const LinearOperator< Range_1, Domain_1 > &A_inv, const LinearOperator< Range_2, Domain_1 > &C, const Range_1 &f, const Range_2 &g)