From: Wolfgang Bangerth Date: Sat, 25 Oct 2014 02:31:40 +0000 (-0500) Subject: Add a mechanism to attach slots to the signal that now controls convergence. X-Git-Tag: v8.2.0-rc1~92^2~1 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e0e3ea8b2fde9142d1c62937ae032c7de71bf703;p=dealii.git Add a mechanism to attach slots to the signal that now controls convergence. Document this with an example that illustrates how we can observe the iteration in process. --- diff --git a/doc/doxygen/images/cg-monitor-smoothing-0.png b/doc/doxygen/images/cg-monitor-smoothing-0.png new file mode 100644 index 0000000000..88476efaf2 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 index 0000000000..93985d8350 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 index 0000000000..da9bb014ac 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 index 0000000000..92e4c81bd6 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 index 0000000000..d1bd7aef6c 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 index 0000000000..43e5707a88 Binary files /dev/null and b/doc/doxygen/images/cg-monitor-smoothing-5.png differ diff --git a/doc/news/changes.h b/doc/news/changes.h index ce74a29e2b..7dc07cdaca 100644 --- a/doc/news/changes.h +++ b/doc/news/changes.h @@ -39,6 +39,15 @@ inconvenience this causes.

    +
  1. Removed: The base class to the iterative linear solvers, Solver, + received a SolverControl object upon construction and had a member + function control() 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. +
    + (Wolfgang Bangerth, 2014/10/24) +
  2. +
  3. Removed: The constructor of the Utilities::MPI::MPI_InitFinalize class used to interpret a last argument equal to numbers::invalid_unsigned_int as "create as many threads as there are processor cores on the current @@ -110,6 +119,15 @@ inconvenience this causes.
      +
    1. 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. +
      + (Wolfgang Bangerth, 2014/10/24) +
    2. +
    3. 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. diff --git a/include/deal.II/lac/solver.h b/include/deal.II/lac/solver.h index 327f7e4e6f..7431309c6e 100644 --- a/include/deal.II/lac/solver.h +++ b/include/deal.II/lac/solver.h @@ -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 class Vector; * way to give these additional data to the @p SolverSelector object for each * solver which it may use. * + * + *

      Observing the progress of linear solver iterations

      + * + * 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 signal 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 slots + * 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 this argument has been bound using the + * std_cxx11::bind 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 ¤t_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 this 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 Step3::solve() 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 std_cxx11::bind here ensures that we convert + * the member function with its three arguments plus the this + * pointer, to a function that only takes three arguments, by fixing + * the implicit this argument of the function to the + * this 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 + * + * + * @image html "cg-monitor-smoothing-0.png" + * + * + * @image html "cg-monitor-smoothing-1.png" + * + * + * @image html "cg-monitor-smoothing-2.png" + * + * + * + * + * @image html "cg-monitor-smoothing-3.png" + * + * + * @image html "cg-monitor-smoothing-4.png" + * + * + * @image html "cg-monitor-smoothing-5.png" + * + * + * + * * @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 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 &slot); + + protected: /** @@ -313,10 +505,10 @@ Solver::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::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 +inline +boost::signals2::connection +Solver:: +connect (const std_cxx11::function &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 index 0000000000..aff175969f --- /dev/null +++ b/tests/lac/solver_monitor.cc @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +SolverControl::State monitor_norm (const unsigned int iteration, + const double check_value, + const Vector ¤t_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 ¤t_iterate) +{ + deallog << " Mean=" << current_iterate.mean_value() << std::endl; + return SolverControl::success; +} + + + +template +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 A(structure); + testproblem.five_point(A); + + PreconditionSSOR<> prec_ssor; + prec_ssor.initialize(A, 1.2); + + Vector f(dim); + Vector u(dim); + Vector 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 index 0000000000..98090021e0 --- /dev/null +++ b/tests/lac/solver_monitor.output @@ -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 index 0000000000..eeef090818 --- /dev/null +++ b/tests/lac/solver_monitor_disconnect.cc @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +SolverControl::State monitor_norm (const unsigned int iteration, + const double check_value, + const Vector ¤t_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 ¤t_iterate) +{ + deallog << " Mean=" << current_iterate.mean_value() << std::endl; + return SolverControl::success; +} + + + +template +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 A(structure); + testproblem.five_point(A); + + PreconditionSSOR<> prec_ssor; + prec_ssor.initialize(A, 1.2); + + Vector f(dim); + Vector u(dim); + Vector 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 index 0000000000..ba4c75c6c8 --- /dev/null +++ b/tests/lac/solver_monitor_disconnect.output @@ -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