]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Add a mechanism to attach slots to the signal that now controls convergence.
authorWolfgang Bangerth <bangerth@math.tamu.edu>
Sat, 25 Oct 2014 02:31:40 +0000 (21:31 -0500)
committerWolfgang Bangerth <bangerth@math.tamu.edu>
Thu, 30 Oct 2014 22:24:37 +0000 (17:24 -0500)
Document this with an example that illustrates how we can observe
the iteration in process.

12 files changed:
doc/doxygen/images/cg-monitor-smoothing-0.png [new file with mode: 0644]
doc/doxygen/images/cg-monitor-smoothing-1.png [new file with mode: 0644]
doc/doxygen/images/cg-monitor-smoothing-2.png [new file with mode: 0644]
doc/doxygen/images/cg-monitor-smoothing-3.png [new file with mode: 0644]
doc/doxygen/images/cg-monitor-smoothing-4.png [new file with mode: 0644]
doc/doxygen/images/cg-monitor-smoothing-5.png [new file with mode: 0644]
doc/news/changes.h
include/deal.II/lac/solver.h
tests/lac/solver_monitor.cc [new file with mode: 0644]
tests/lac/solver_monitor.output [new file with mode: 0644]
tests/lac/solver_monitor_disconnect.cc [new file with mode: 0644]
tests/lac/solver_monitor_disconnect.output [new file with mode: 0644]

diff --git a/doc/doxygen/images/cg-monitor-smoothing-0.png b/doc/doxygen/images/cg-monitor-smoothing-0.png
new file mode 100644 (file)
index 0000000..88476ef
Binary files /dev/null and b/doc/doxygen/images/cg-monitor-smoothing-0.png differ
diff --git a/doc/doxygen/images/cg-monitor-smoothing-1.png b/doc/doxygen/images/cg-monitor-smoothing-1.png
new file mode 100644 (file)
index 0000000..93985d8
Binary files /dev/null and b/doc/doxygen/images/cg-monitor-smoothing-1.png differ
diff --git a/doc/doxygen/images/cg-monitor-smoothing-2.png b/doc/doxygen/images/cg-monitor-smoothing-2.png
new file mode 100644 (file)
index 0000000..da9bb01
Binary files /dev/null and b/doc/doxygen/images/cg-monitor-smoothing-2.png differ
diff --git a/doc/doxygen/images/cg-monitor-smoothing-3.png b/doc/doxygen/images/cg-monitor-smoothing-3.png
new file mode 100644 (file)
index 0000000..92e4c81
Binary files /dev/null and b/doc/doxygen/images/cg-monitor-smoothing-3.png differ
diff --git a/doc/doxygen/images/cg-monitor-smoothing-4.png b/doc/doxygen/images/cg-monitor-smoothing-4.png
new file mode 100644 (file)
index 0000000..d1bd7ae
Binary files /dev/null and b/doc/doxygen/images/cg-monitor-smoothing-4.png differ
diff --git a/doc/doxygen/images/cg-monitor-smoothing-5.png b/doc/doxygen/images/cg-monitor-smoothing-5.png
new file mode 100644 (file)
index 0000000..43e5707
Binary files /dev/null and b/doc/doxygen/images/cg-monitor-smoothing-5.png differ
index ce74a29e2bad79453a4d3e3f8cae3b1ed14e44d2..7dc07cdaca75ed0a83443db2c82f244a5f29cfe1 100644 (file)
@@ -39,6 +39,15 @@ inconvenience this causes.
 </p>
 
 <ol>
+  <li> Removed: The base class to the iterative linear solvers, Solver,
+  received a SolverControl object upon construction and had a member
+  function <code>control()</code> that returned a reference to the
+  object previously passed in. The class now no longer stores such
+  a reference, and consequently, the function has been removed.
+  <br>
+  (Wolfgang Bangerth, 2014/10/24)
+  </li>
+
   <li> Removed: The constructor of the Utilities::MPI::MPI_InitFinalize
   class used to interpret a last argument equal to numbers::invalid_unsigned_int
   as "<i>create as many threads as there are processor cores on the current
@@ -110,6 +119,15 @@ inconvenience this causes.
 
 
 <ol>
+  <li> New: The classes implementing iterative solvers have gained
+  a mechanism by which it is possible to observe the progress of
+  the iterations, or to influence when to stop the iteration. The
+  documentation of the Solver class now contains an extended
+  discussion and example of this functionality.
+  <br>
+  (Wolfgang Bangerth, 2014/10/24)
+  </li>
+
   <li> New: There is now a section in the introduction of step-36 that
   discusses the interaction of Dirichlet boundary values and the solution
   of eigenvalue problems.
index 327f7e4e6f95ec98818675e6c999172b06b4e744..7431309c6eb59b1a3efff126ce5dd7e02f1d582c 100644 (file)
@@ -1,6 +1,6 @@
 // ---------------------------------------------------------------------
 //
-// Copyright (C) 1998 - 2013 by the deal.II authors
+// Copyright (C) 1998 - 2014 by the deal.II authors
 //
 // This file is part of the deal.II library.
 //
@@ -150,8 +150,163 @@ template <typename number> class Vector;
  * way to give these additional data to the @p SolverSelector object for each
  * solver which it may use.
  *
+ *
+ * <h3>Observing the progress of linear solver iterations</h3>
+ *
+ * The Solver class, being the base class for all of the iterative solvers such
+ * as SolverCG, SolverGMRES, etc, provides the facilities by which actual solver
+ * implementations determine whether the iteration is converged, not yet
+ * converged, or has failed. Typically, this is done using an object of type
+ * SolverControl that is passed to the solver classes's constructors and from
+ * them down to the constructor of this base class. Every one of the tutorial
+ * programs that solves a linear problem (starting with step-3) uses this
+ * method and it is described in detail there. However, the underlying mechanism
+ * is more general and allows for many other uses to observe how the linear
+ * solver iterations progress.
+ *
+ * The basic approach is that the iterative solvers invoke a <i>signal</i> at
+ * the end of each iteration to determine whether the solution is converged.
+ * A signal is a class that has, conceptually, a list of pointers to functions
+ * and every time the signal is invoked, each of these functions are called.
+ * In the language of signals, the functions called are called <i>slots</i>
+ * and one can attach any number of slots to a signal.
+ * (The implementation of signals and slots we use here is the one from the
+ * BOOST.signals2 library.) A number of details may clarify what is happening
+ * underneath:
+ * - In reality, the signal object does not store pointers to functions, but
+ *   function objects as slots. Each slot must conform to a particular
+ *   signature: here, it is an object that can be called with three arguments
+ *   (the number of the current linear iteration, the current residual, and
+ *   the current iterate; more specifics are discussed in the documentation of
+ *   the connect() function). A pointer to a function with this argument list
+ *   satisfies the requirements, but you can also pass a member function
+ *   whose <code>this</code> argument has been bound using the
+ *   <code>std_cxx11::bind</code> mechanism (see the example below).
+ * - Each of the slots will return a value that indicates whether
+ *   the iteration should continue, should stop because it has succeeded,
+ *   or stop because it has failed. The return type of slots is therefore
+ *   of type SolverControl::State. The returned values from all of the
+ *   slots will then have to be combined before they are returned to the
+ *   iterative solver that invoked the signal. The way this works is that
+ *   if at least one slot returned SolverControl::failure, then the
+ *   combined value is SolverControl::failure; otherwise, if at least
+ *   one slot returned SolverControl::iterate, then this is going to be
+ *   the return value of the signal; finally, only if all slots return
+ *   SolverControl::success will the signal's return value be
+ *   SolverControl::success.
+ * - It may of course be that a particular
+ *   slot has been connected to the signal only to observe how the
+ *   solution or a specific part of it converges, but has no particular
+ *   opinion on whether the iteration should continue or not. In such
+ *   cases, the slot should just return SolverControl::success, which
+ *   is the weakest of all return values according to the rules laid
+ *   out above.
+ *
+ * Given all this, it should now be obvious how the SolverControl
+ * object fits into this scheme: when a SolverControl object is passed
+ * to the constructor of the current class, we simply connect the
+ * SolverControl::check() function of that object as a slot to the
+ * signal we maintain here. In other words, since a Solver object
+ * is always constructed using a SolverControl object, there is
+ * always at least one slot associated with the signal, namely the
+ * one that determines convergence.
+ *
+ * On the other hand, using the connect() member function, it is
+ * possible to connect any number of other slots to the signal to
+ * observe whatever it is you want to observe. The connect() function
+ * also returns an object that describes the connection from the
+ * signal to the slot, and the corresponding BOOST functions then allow
+ * you to disconnect the slot if you want.
+ *
+ * An example may illuminate these issues. In the step-3 tutorial
+ * program, let us add a member function as follows to the main class:
+ * @code
+ *  SolverControl::State
+ *  Step3::write_intermediate_solution (const unsigned int    iteration,
+ *                                      const double          , //check_value
+ *                                      const Vector<double> &current_iterate) const
+ *    {
+ *      DataOut<2> data_out;
+ *      data_out.attach_dof_handler (dof_handler);
+ *      data_out.add_data_vector (current_iterate, "solution");
+ *      data_out.build_patches ();
+ *
+ *      std::ofstream output ((std::string("solution-")
+ *                             + Utilities::int_to_string(iteration,4) + ".vtu").c_str());
+ *      data_out.write_vtu (output);
+ *
+ *      return SolverControl::success;
+ *    }
+ * @endcode
+ * The function satisfies the signature necessary to be a slot for the
+ * signal discussed above, with the exception that it is a member
+ * function and consequently requires a <code>this</code> pointer.
+ * What the function does is to take the vector given as last
+ * argument and write it into a file in VTU format with a file
+ * name derived from the number of the iteration.
+ *
+ * This function can then be hooked into the CG solver by modifying
+ * the <code>Step3::solve()</code> function as follows:
+ * @code
+ * void Step3::solve ()
+ * {
+ *   SolverControl           solver_control (1000, 1e-12);
+ *   SolverCG<>              solver (solver_control);
+ *
+ *   solver.connect (std_cxx11::bind (&Step3::write_intermediate_solution,
+ *                                    this,
+ *                                    std_cxx11::_1,
+ *                                    std_cxx11::_2,
+ *                                    std_cxx11::_3));
+ *   solver.solve (system_matrix, solution, system_rhs,
+ *                 PreconditionIdentity());
+ * }
+ * @endcode
+ * The use of <code>std_cxx11::bind</code> here ensures that we convert
+ * the member function with its three arguments plus the <code>this</code>
+ * pointer, to a function that only takes three arguments, by fixing
+ * the implicit <code>this</code> argument of the function to the
+ * <code>this</code> pointer in the current function.
+ *
+ * It is well understood that the CG method is a smoothing iteration (in
+ * the same way as the more commonly used Jacobi or SSOR iterations are
+ * smoothers). The code above therefore allows to observe how the solution
+ * becomes smoother and smoother in every iteration. This is best
+ * observed by initializing the solution vector with randomly distributed
+ * numbers in $[-1,1]$, using code such as
+ * @code
+ *   for (unsigned int i=0; i<solution.size(); ++i)
+ *     solution(i) = 2.*rand()/RAND_MAX-1;
+ * @endcode
+ * Using this, the slot will then generate files that when visualized
+ * look like this over the course of iterations zero to five:
+ * <table>
+ * <tr>
+ *   <td>
+ *     @image html "cg-monitor-smoothing-0.png"
+ *   </td>
+ *   <td>
+ *     @image html "cg-monitor-smoothing-1.png"
+ *   </td>
+ *   <td>
+ *     @image html "cg-monitor-smoothing-2.png"
+ *   </td>
+ * </tr>
+ * <tr>
+ *   <td>
+ *     @image html "cg-monitor-smoothing-3.png"
+ *   </td>
+ *   <td>
+ *     @image html "cg-monitor-smoothing-4.png"
+ *   </td>
+ *   <td>
+ *     @image html "cg-monitor-smoothing-5.png"
+ *   </td>
+ * </tr>
+ * </table>
+ *
  * @ingroup Solvers
- * @author Wolfgang Bangerth, Guido Kanschat, Ralf Hartmann, 1997-2001, 2005
+ * @author Wolfgang Bangerth, Guido Kanschat, Ralf Hartmann, 1997-2001, 2005, 2014
  */
 template <class VECTOR = Vector<double> >
 class Solver : public Subscriptor
@@ -192,7 +347,44 @@ public:
    * as long as that of the solver
    * object.
    */
-  Solver (SolverControl        &solver_control);
+  Solver (SolverControl &solver_control);
+
+  /**
+   * Connect a function object that will be called periodically within
+   * iterative solvers. This function is used to attach monitors to
+   * iterative solvers, either to determine when convergence has happened,
+   * or simply to observe the progress of an iteration. See the documentation
+   * of this class for more information.
+   *
+   * @param slot A function object specified here will, with
+   *   each call, receive the number of the current iteration,
+   *   the value that is used to check for convergence (typically the residual
+   *   of the current iterate with respect to the linear system to be solved)
+   *   and the currently best available guess for the current iterate.
+   *   Note that some solvers do not update the approximate solution in every
+   *   iteration but only after convergence or failure has been determined
+   *   (GMRES is an example); in such cases, the vector passed as the last
+   *   argument to the signal is simply the best approximate at the time
+   *   the signal is called, but not the vector that will be returned if
+   *   the signal's return value indicates that the iteration should be
+   *   terminated. The function object must return a SolverControl::State
+   *   value that indicates whether the iteration should continue, has
+   *   failed, or has succeeded. The results of all connected functions
+   *   will then be combined to determine what should happen with the
+   *   iteration.
+   *
+   * @return A connection object that represents the connection from the
+   *   signal to the function object. It can be used to disconnect the
+   *   function object again from the signal. See the documentation of
+   *   the BOOST Signals2 library for more information on connection
+   *   management.
+   */
+  boost::signals2::connection
+  connect (const std_cxx11::function<SolverControl::State (const unsigned int iteration,
+                                                           const double        check_value,
+                                                           const VECTOR       &current_iterate)> &slot);
+
+
 
 protected:
   /**
@@ -313,10 +505,10 @@ Solver<VECTOR>::Solver (SolverControl        &solver_control,
   // only takes two arguments, the iteration and the check_value, and so
   // we simply ignore the third argument that is passed in whenever the
   // signal is executed
-  iteration_status.connect (std_cxx11::bind(&SolverControl::check,
-                                            std_cxx11::ref(solver_control),
-                                            std_cxx11::_1,
-                                            std_cxx11::_2));
+  connect (std_cxx11::bind(&SolverControl::check,
+                           std_cxx11::ref(solver_control),
+                           std_cxx11::_1,
+                           std_cxx11::_2));
 }
 
 
@@ -332,14 +524,26 @@ Solver<VECTOR>::Solver (SolverControl        &solver_control)
   // only takes two arguments, the iteration and the check_value, and so
   // we simply ignore the third argument that is passed in whenever the
   // signal is executed
-  iteration_status.connect (std_cxx11::bind(&SolverControl::check,
-                                            std_cxx11::ref(solver_control),
-                                            std_cxx11::_1,
-                                            std_cxx11::_2));
+  connect (std_cxx11::bind(&SolverControl::check,
+                           std_cxx11::ref(solver_control),
+                           std_cxx11::_1,
+                           std_cxx11::_2));
 }
 
 
 
+template<class VECTOR>
+inline
+boost::signals2::connection
+Solver<VECTOR>::
+connect (const std_cxx11::function<SolverControl::State (const unsigned int iteration,
+                                                         const double        check_value,
+                                                         const VECTOR       &current_iterate)> &slot)
+{
+  return iteration_status.connect (slot);
+}
+
+
 
 DEAL_II_NAMESPACE_CLOSE
 
diff --git a/tests/lac/solver_monitor.cc b/tests/lac/solver_monitor.cc
new file mode 100644 (file)
index 0000000..aff1759
--- /dev/null
@@ -0,0 +1,141 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2014 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+// use signals to monitor solutions converging
+
+
+#include "../tests.h"
+#include "testmatrix.h"
+#include <cmath>
+#include <fstream>
+#include <iomanip>
+#include <deal.II/base/logstream.h>
+#include <deal.II/lac/sparse_matrix.h>
+#include <deal.II/lac/vector.h>
+#include <deal.II/lac/vector_memory.h>
+#include <deal.II/lac/solver_control.h>
+#include <deal.II/lac/solver_cg.h>
+#include <deal.II/lac/solver_gmres.h>
+#include <deal.II/lac/solver_minres.h>
+#include <deal.II/lac/solver_bicgstab.h>
+#include <deal.II/lac/solver_richardson.h>
+#include <deal.II/lac/solver_qmrs.h>
+#include <deal.II/lac/precondition.h>
+
+
+SolverControl::State monitor_norm (const unsigned int    iteration,
+                                  const double          check_value,
+                                  const Vector<double> &current_iterate)
+{
+  deallog << "   -- " << iteration << ' ' << check_value << std::endl;
+  deallog << "   Norm=" << current_iterate.l2_norm() << std::endl;
+  return SolverControl::success;
+}
+
+
+SolverControl::State monitor_mean (const unsigned int    iteration,
+                                  const double          check_value,
+                                  const Vector<double> &current_iterate)
+{
+  deallog << "   Mean=" << current_iterate.mean_value() << std::endl;
+  return SolverControl::success;
+}
+
+
+
+template<class SOLVER, class MATRIX, class VECTOR, class PRECONDITION>
+void
+check_solve( SOLVER &solver, const MATRIX &A,
+             VECTOR &u, VECTOR &f, const PRECONDITION &P)
+{
+  u = 0.;
+  f = 1.;
+  try
+    {
+      solver.solve(A,u,f,P);
+    }
+  catch (dealii::SolverControl::NoConvergence &e)
+    {
+      deallog << "Exception: " << e.get_exc_name() << std::endl;
+    }
+}
+
+int main()
+{
+  std::ofstream logfile("output");
+//  logfile.setf(std::ios::fixed);
+  deallog << std::setprecision(4);
+  deallog.attach(logfile);
+  deallog.depth_console(0);
+  deallog.threshold_double(1.e-10);
+
+  GrowingVectorMemory<> mem;
+
+  SolverControl control(100, 1.e-3);
+
+  // create CG and GMRES solvers and attach monitors to it
+  SolverCG<> cg(control, mem);
+  cg.connect (&monitor_norm);
+  cg.connect (&monitor_mean);  
+
+  SolverGMRES<> gmres(control, mem, 8);
+  gmres.connect (&monitor_norm);
+  gmres.connect (&monitor_mean);  
+
+  for (unsigned int size=4; size <= 30; size *= 3)
+    {
+      unsigned int dim = (size-1)*(size-1);
+
+      deallog << "Size " << size << " Unknowns " << dim << std::endl;
+
+      // Make matrix
+      FDMatrix testproblem(size, size);
+      SparsityPattern structure(dim, dim, 5);
+      testproblem.five_point_structure(structure);
+      structure.compress();
+      SparseMatrix<double>  A(structure);
+      testproblem.five_point(A);
+
+      PreconditionSSOR<> prec_ssor;
+      prec_ssor.initialize(A, 1.2);
+
+      Vector<double>  f(dim);
+      Vector<double>  u(dim);
+      Vector<double> res(dim);
+
+      f = 1.;
+      u = 1.;
+
+      A.residual(res,u,f);
+      A.SOR(res);
+      res.add(1.,u);
+      A.SOR_step(u,f);
+      res.add(-1.,u);
+
+      deallog << "SOR-diff:" << res *res << std::endl;
+
+      try
+        {
+          check_solve(cg,A,u,f,prec_ssor);
+          check_solve(gmres,A,u,f,prec_ssor);
+        }
+      catch (std::exception &e)
+        {
+          std::cerr << "Exception: " << e.what() << std::endl;
+        }
+    }
+}
+
diff --git a/tests/lac/solver_monitor.output b/tests/lac/solver_monitor.output
new file mode 100644 (file)
index 0000000..9809002
--- /dev/null
@@ -0,0 +1,94 @@
+
+DEAL::Size 4 Unknowns 9
+DEAL::SOR-diff:0
+DEAL:cg::Starting value 3.000
+DEAL:cg::   -- 0 3.000
+DEAL:cg::   Norm=0
+DEAL:cg::   Mean=0
+DEAL:cg::   -- 1 0.7126
+DEAL:cg::   Norm=2.432
+DEAL:cg::   Mean=0.8020
+DEAL:cg::   -- 2 0.06314
+DEAL:cg::   Norm=2.493
+DEAL:cg::   Mean=0.8194
+DEAL:cg::   -- 3 0.001494
+DEAL:cg::   Norm=2.494
+DEAL:cg::   Mean=0.8194
+DEAL:cg::Convergence step 4 value 6.018e-05
+DEAL:cg::   -- 4 6.018e-05
+DEAL:cg::   Norm=2.494
+DEAL:cg::   Mean=0.8194
+DEAL:GMRES::Starting value 1.920
+DEAL:GMRES::   -- 0 1.920
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::   -- 1 0.1979
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::   -- 2 0.009469
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::Convergence step 3 value 0.0003574
+DEAL:GMRES::   -- 3 0.0003574
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL::Size 12 Unknowns 121
+DEAL::SOR-diff:0
+DEAL:cg::Starting value 11.00
+DEAL:cg::   -- 0 11.00
+DEAL:cg::   Norm=0
+DEAL:cg::   Mean=0
+DEAL:cg::   -- 1 12.13
+DEAL:cg::   Norm=50.48
+DEAL:cg::   Mean=4.496
+DEAL:cg::   -- 2 4.992
+DEAL:cg::   Norm=68.00
+DEAL:cg::   Mean=5.737
+DEAL:cg::   -- 3 1.090
+DEAL:cg::   Norm=70.78
+DEAL:cg::   Mean=5.884
+DEAL:cg::   -- 4 0.1907
+DEAL:cg::   Norm=70.88
+DEAL:cg::   Mean=5.889
+DEAL:cg::   -- 5 0.04614
+DEAL:cg::   Norm=70.89
+DEAL:cg::   Mean=5.889
+DEAL:cg::   -- 6 0.007982
+DEAL:cg::   Norm=70.88
+DEAL:cg::   Mean=5.889
+DEAL:cg::   -- 7 0.001234
+DEAL:cg::   Norm=70.88
+DEAL:cg::   Mean=5.889
+DEAL:cg::Convergence step 8 value 0.0005816
+DEAL:cg::   -- 8 0.0005816
+DEAL:cg::   Norm=70.88
+DEAL:cg::   Mean=5.889
+DEAL:GMRES::Starting value 13.27
+DEAL:GMRES::   -- 0 13.27
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::   -- 1 7.177
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::   -- 2 2.514
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::   -- 3 0.4482
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::   -- 4 0.1000
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::   -- 5 0.01999
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::   -- 6 0.002554
+DEAL:GMRES::   Norm=0
+DEAL:GMRES::   Mean=0
+DEAL:GMRES::   -- 6 0.002554
+DEAL:GMRES::   Norm=70.88
+DEAL:GMRES::   Mean=5.889
+DEAL:GMRES::Convergence step 7 value 0.0008206
+DEAL:GMRES::   -- 7 0.0008206
+DEAL:GMRES::   Norm=70.88
+DEAL:GMRES::   Mean=5.889
diff --git a/tests/lac/solver_monitor_disconnect.cc b/tests/lac/solver_monitor_disconnect.cc
new file mode 100644 (file)
index 0000000..eeef090
--- /dev/null
@@ -0,0 +1,140 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2014 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+// use signals to monitor solutions converging. test that we can
+// disconnect from a signal
+
+
+#include "../tests.h"
+#include "testmatrix.h"
+#include <cmath>
+#include <fstream>
+#include <iomanip>
+#include <deal.II/base/logstream.h>
+#include <deal.II/lac/sparse_matrix.h>
+#include <deal.II/lac/vector.h>
+#include <deal.II/lac/vector_memory.h>
+#include <deal.II/lac/solver_control.h>
+#include <deal.II/lac/solver_cg.h>
+#include <deal.II/lac/solver_gmres.h>
+#include <deal.II/lac/solver_minres.h>
+#include <deal.II/lac/solver_bicgstab.h>
+#include <deal.II/lac/solver_richardson.h>
+#include <deal.II/lac/solver_qmrs.h>
+#include <deal.II/lac/precondition.h>
+
+
+SolverControl::State monitor_norm (const unsigned int    iteration,
+                                  const double          check_value,
+                                  const Vector<double> &current_iterate)
+{
+  deallog << "   -- " << iteration << ' ' << check_value << std::endl;
+  deallog << "   Norm=" << current_iterate.l2_norm() << std::endl;
+  return SolverControl::success;
+}
+
+
+SolverControl::State monitor_mean (const unsigned int    iteration,
+                                  const double          check_value,
+                                  const Vector<double> &current_iterate)
+{
+  deallog << "   Mean=" << current_iterate.mean_value() << std::endl;
+  return SolverControl::success;
+}
+
+
+
+template<class SOLVER, class MATRIX, class VECTOR, class PRECONDITION>
+void
+check_solve( SOLVER &solver, const MATRIX &A,
+             VECTOR &u, VECTOR &f, const PRECONDITION &P)
+{
+  u = 0.;
+  f = 1.;
+  try
+    {
+      solver.solve(A,u,f,P);
+    }
+  catch (dealii::SolverControl::NoConvergence &e)
+    {
+      deallog << "Exception: " << e.get_exc_name() << std::endl;
+    }
+}
+
+int main()
+{
+  std::ofstream logfile("output");
+//  logfile.setf(std::ios::fixed);
+  deallog << std::setprecision(4);
+  deallog.attach(logfile);
+  deallog.depth_console(0);
+  deallog.threshold_double(1.e-10);
+
+  GrowingVectorMemory<> mem;
+
+  SolverControl control(100, 1.e-3);
+
+  // create CG and GMRES solvers and attach monitors to it
+  SolverCG<> cg(control, mem);
+  boost::signals2::connection cg_c1 = cg.connect (&monitor_norm);
+  boost::signals2::connection cg_c2 = cg.connect (&monitor_mean);  
+
+  for (unsigned int size=4; size <= 12; size *= 3)
+    {
+      unsigned int dim = (size-1)*(size-1);
+
+      deallog << "Size " << size << " Unknowns " << dim << std::endl;
+
+      // Make matrix
+      FDMatrix testproblem(size, size);
+      SparsityPattern structure(dim, dim, 5);
+      testproblem.five_point_structure(structure);
+      structure.compress();
+      SparseMatrix<double>  A(structure);
+      testproblem.five_point(A);
+
+      PreconditionSSOR<> prec_ssor;
+      prec_ssor.initialize(A, 1.2);
+
+      Vector<double>  f(dim);
+      Vector<double>  u(dim);
+      Vector<double> res(dim);
+
+      f = 1.;
+      u = 1.;
+
+      A.residual(res,u,f);
+      A.SOR(res);
+      res.add(1.,u);
+      A.SOR_step(u,f);
+      res.add(-1.,u);
+
+      deallog << "SOR-diff:" << res *res << std::endl;
+
+      try
+        {
+          check_solve(cg,A,u,f,prec_ssor);
+        }
+      catch (std::exception &e)
+        {
+          std::cerr << "Exception: " << e.what() << std::endl;
+        }
+
+      // disconnect one of the signals
+      cg_c1.disconnect();
+    }
+}
+
diff --git a/tests/lac/solver_monitor_disconnect.output b/tests/lac/solver_monitor_disconnect.output
new file mode 100644 (file)
index 0000000..ba4c75c
--- /dev/null
@@ -0,0 +1,33 @@
+
+DEAL::Size 4 Unknowns 9
+DEAL::SOR-diff:0
+DEAL:cg::Starting value 3.000
+DEAL:cg::   -- 0 3.000
+DEAL:cg::   Norm=0
+DEAL:cg::   Mean=0
+DEAL:cg::   -- 1 0.7126
+DEAL:cg::   Norm=2.432
+DEAL:cg::   Mean=0.8020
+DEAL:cg::   -- 2 0.06314
+DEAL:cg::   Norm=2.493
+DEAL:cg::   Mean=0.8194
+DEAL:cg::   -- 3 0.001494
+DEAL:cg::   Norm=2.494
+DEAL:cg::   Mean=0.8194
+DEAL:cg::Convergence step 4 value 6.018e-05
+DEAL:cg::   -- 4 6.018e-05
+DEAL:cg::   Norm=2.494
+DEAL:cg::   Mean=0.8194
+DEAL::Size 12 Unknowns 121
+DEAL::SOR-diff:0
+DEAL:cg::Starting value 11.00
+DEAL:cg::   Mean=0
+DEAL:cg::   Mean=4.496
+DEAL:cg::   Mean=5.737
+DEAL:cg::   Mean=5.884
+DEAL:cg::   Mean=5.889
+DEAL:cg::   Mean=5.889
+DEAL:cg::   Mean=5.889
+DEAL:cg::   Mean=5.889
+DEAL:cg::Convergence step 8 value 0.0005816
+DEAL:cg::   Mean=5.889

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.